You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@james.apache.org by rc...@apache.org on 2021/04/27 02:53:41 UTC

[james-project] branch 3.6.x updated (5bdee08 -> 2b4fa80)

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

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


    from 5bdee08  JAMES-3261 Guice memory docker should reuse guice memory ZIP app
     new 9fedbf7  JAMES-3557 Changes collectors should be ordered
     new 0a1cf6d  JAMES-3277 Distinct uids before calling toRanges
     new 50bd76c  JAMES-3557 */changes: Fail explicitly when too much entries on a single change
     new 0eed325  JAMES-3557 JMAP */changes: Increase default maxChanges 5 -> 256
     new 0ae5c19  JAMES-3434 Refactoring: EmailSubmissionSetMethod should not rely on nested clases
     new 2b4fa80  JAMES-3525 verifyIdentity should not fail on null sender

The 6 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 ...ractSenderAuthIdentifyVerificationRcptHook.java |   6 +-
 .../modules/mailbox/CassandraMailboxModule.java    |   4 +
 .../james/modules/mailbox/MemoryMailboxModule.java |   4 +
 .../change/CassandraEmailChangeRepository.java     |  15 +--
 .../change/CassandraMailboxChangeRepository.java   |  15 +--
 .../change/CassandraEmailChangeRepositoryTest.java |   2 +-
 .../CassandraMailboxChangeRepositoryTest.java      |   3 +-
 ...e.java => CanNotCalculateChangesException.java} |   8 +-
 .../apache/james/jmap/api/change/EmailChanges.java |   6 +-
 .../james/jmap/api/change/MailboxChanges.java      |   6 +-
 .../memory/change/MemoryEmailChangeRepository.java |  14 ++-
 .../change/MemoryMailboxChangeRepository.java      |  18 ++--
 .../api/change/EmailChangeRepositoryContract.java  |  28 +++---
 .../change/MailboxChangeRepositoryContract.java    |  12 ++-
 .../change/MemoryEmailChangeRepositoryTest.java    |   3 +-
 .../change/MemoryMailboxChangeRepositoryTest.java  |   4 +-
 .../james/smtp/SmtpIdentityVerificationTest.java   |  37 +++++++
 .../DistributedEmailChangeMethodTest.java          |   9 +-
 .../DistributedMailboxChangeMethodTest.java        |   9 +-
 .../contract/EmailChangesMethodContract.scala      | 110 +++++++++++++++++++++
 .../memory/MemoryEmailChangesMethodTest.java       |   9 +-
 .../memory/MemoryMailboxChangesMethodTest.java     |   9 +-
 .../james/jmap/method/EmailChangesMethod.scala     |   8 +-
 .../jmap/method/EmailSetUpdatePerformer.scala      |   2 +-
 .../jmap/method/EmailSubmissionSetMethod.scala     |  55 +++++------
 .../james/jmap/method/MailboxChangesMethod.scala   |   8 +-
 .../jmap/change/MailboxChangeListenerTest.scala    |   9 +-
 .../org/apache/james/utils/SMTPMessageSender.java  |  11 +++
 28 files changed, 326 insertions(+), 98 deletions(-)
 copy server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/{JmapChange.java => CanNotCalculateChangesException.java} (88%)

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


[james-project] 02/06: JAMES-3277 Distinct uids before calling toRanges

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0a1cf6dfa13982c9543f09eec0e84087796cc34e
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 9 11:58:26 2021 +0700

    JAMES-3277 Distinct uids before calling toRanges
    
    Duplicates prevented toRanges to work properly...
---
 .../scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
index d40273b..2860a54 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSetUpdatePerformer.scala
@@ -140,7 +140,7 @@ class EmailSetUpdatePerformer @Inject() (serializer: EmailSetSerializer,
   private def asRanges(metaData: Map[MessageId, Traversable[ComposedMessageIdWithMetaData]]) =
     MessageRange.toRanges(metaData.values
       .flatten.map(_.getComposedMessageId.getUid)
-      .toList.asJava)
+      .toList.distinct.asJava)
       .asScala.toList
 
   private def updateFlagsByRange(mailboxId: MailboxId,

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


[james-project] 05/06: JAMES-3434 Refactoring: EmailSubmissionSetMethod should not rely on nested clases

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0ae5c195e46ca6d89cd491f1229f457e5b97b4e0
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 16 22:51:41 2021 +0700

    JAMES-3434 Refactoring: EmailSubmissionSetMethod should not rely on nested clases
---
 .../jmap/method/EmailSubmissionSetMethod.scala     | 55 +++++++++++-----------
 1 file changed, 27 insertions(+), 28 deletions(-)

diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala
index 544f13b..14904b3 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailSubmissionSetMethod.scala
@@ -36,7 +36,7 @@ import org.apache.james.jmap.core.{ClientId, Id, Invocation, Properties, ServerI
 import org.apache.james.jmap.json.{EmailSubmissionSetSerializer, ResponseSerializer}
 import org.apache.james.jmap.mail.EmailSubmissionSet.EmailSubmissionCreationId
 import org.apache.james.jmap.mail.{EmailSubmissionAddress, EmailSubmissionCreationRequest, EmailSubmissionCreationResponse, EmailSubmissionId, EmailSubmissionSetRequest, EmailSubmissionSetResponse, Envelope}
-import org.apache.james.jmap.method.EmailSubmissionSetMethod.{LOGGER, MAIL_METADATA_USERNAME_ATTRIBUTE}
+import org.apache.james.jmap.method.EmailSubmissionSetMethod.{CreationFailure, CreationResult, CreationResults, CreationSuccess, LOGGER, MAIL_METADATA_USERNAME_ATTRIBUTE}
 import org.apache.james.jmap.routes.{ProcessingContext, SessionSupplier}
 import org.apache.james.lifecycle.api.{LifecycleUtil, Startable}
 import org.apache.james.mailbox.model.{FetchGroup, MessageResult}
@@ -62,31 +62,6 @@ object EmailSubmissionSetMethod {
   val noRecipients: SetErrorType = "noRecipients"
   val forbiddenFrom: SetErrorType = "forbiddenFrom"
   val forbiddenMailFrom: SetErrorType = "forbiddenMailFrom"
-}
-
-case class EmailSubmissionCreationParseException(setError: SetError) extends Exception
-case class NoRecipientException() extends Exception
-case class ForbiddenFromException(from: String) extends Exception
-case class ForbiddenMailFromException(from: List[String]) extends Exception
-
-case class MessageMimeMessageSource(id: String, message: MessageResult) extends MimeMessageSource {
-  override def getSourceId: String = id
-
-  override def getInputStream: InputStream = message.getFullContent.getInputStream
-
-  override def getMessageSize: Long = message.getFullContent.size()
-}
-
-class EmailSubmissionSetMethod @Inject()(serializer: EmailSubmissionSetSerializer,
-                                         messageIdManager: MessageIdManager,
-                                         mailQueueFactory: MailQueueFactory[_ <: MailQueue],
-                                         canSendFrom: CanSendFrom,
-                                         emailSetMethod: EmailSetMethod,
-                                         val metricFactory: MetricFactory,
-                                         val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[EmailSubmissionSetRequest] with Startable {
-  override val methodName: MethodName = MethodName("EmailSubmission/set")
-  override val requiredCapabilities: Set[CapabilityIdentifier] = Set(JMAP_CORE, EMAIL_SUBMISSION)
-  var queue: MailQueue = _
 
   sealed trait CreationResult {
     def emailSubmissionCreationId: EmailSubmissionCreationId
@@ -127,9 +102,33 @@ class EmailSubmissionSetMethod @Inject()(serializer: EmailSubmissionSetSerialize
       }
       .toMap
   }
+}
+
+case class EmailSubmissionCreationParseException(setError: SetError) extends Exception
+case class NoRecipientException() extends Exception
+case class ForbiddenFromException(from: String) extends Exception
+case class ForbiddenMailFromException(from: List[String]) extends Exception
+
+case class MessageMimeMessageSource(id: String, message: MessageResult) extends MimeMessageSource {
+  override def getSourceId: String = id
+
+  override def getInputStream: InputStream = message.getFullContent.getInputStream
+
+  override def getMessageSize: Long = message.getFullContent.size()
+}
+
+class EmailSubmissionSetMethod @Inject()(serializer: EmailSubmissionSetSerializer,
+                                         messageIdManager: MessageIdManager,
+                                         mailQueueFactory: MailQueueFactory[_ <: MailQueue],
+                                         canSendFrom: CanSendFrom,
+                                         emailSetMethod: EmailSetMethod,
+                                         val metricFactory: MetricFactory,
+                                         val sessionSupplier: SessionSupplier) extends MethodRequiringAccountId[EmailSubmissionSetRequest] with Startable {
+  override val methodName: MethodName = MethodName("EmailSubmission/set")
+  override val requiredCapabilities: Set[CapabilityIdentifier] = Set(JMAP_CORE, EMAIL_SUBMISSION)
+  var queue: MailQueue = _
 
-  def init: Unit =
-    queue = mailQueueFactory.createQueue(SPOOL)
+  def init: Unit = queue = mailQueueFactory.createQueue(SPOOL)
 
   @PreDestroy def dispose: Unit =
     Try(queue.close())

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


[james-project] 06/06: JAMES-3525 verifyIdentity should not fail on null sender

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 2b4fa802e3278bdca6bd2ab4a725c8639fb99db1
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Sat Apr 17 13:04:30 2021 +0700

    JAMES-3525 verifyIdentity should not fail on null sender
    
    Before this patch an unchecked error was specified. SMTP error code 430.
    
    ```
    java.lang.IllegalArgumentException: null
    	at com.google.common.base.Preconditions.checkArgument(Preconditions.java:127)
    	at org.apache.james.protocols.smtp.core.AbstractSenderAuthIdentifyVerificationRcptHook.belongsToLocalDomain(AbstractSenderAuthIdentifyVerificationRcptHook.java:89)
    	at org.apache.james.protocols.smtp.core.AbstractSenderAuthIdentifyVerificationRcptHook.doRcpt(AbstractSenderAuthIdentifyVerificationRcptHook.java:66)
    	at org.apache.james.smtpserver.SenderAuthIdentifyVerificationRcptHook.doRcpt(SenderAuthIdentifyVerificationRcptHook.java:59)
    	at org.apache.james.protocols.smtp.hook.RcptHook.doRcpt(RcptHook.java:77)
    ```
    
    After this patch the sender address is explicitly rejected. Error code 503 & no stacktrace.
---
 ...ractSenderAuthIdentifyVerificationRcptHook.java |  6 ++--
 .../james/smtp/SmtpIdentityVerificationTest.java   | 37 ++++++++++++++++++++++
 .../org/apache/james/utils/SMTPMessageSender.java  | 11 +++++++
 3 files changed, 52 insertions(+), 2 deletions(-)

diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
index f93176c..758eaa6 100644
--- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
+++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/AbstractSenderAuthIdentifyVerificationRcptHook.java
@@ -86,8 +86,10 @@ public abstract class AbstractSenderAuthIdentifyVerificationRcptHook implements
     }
 
     private boolean belongsToLocalDomain(MaybeSender maybeSender) {
-        Preconditions.checkArgument(!maybeSender.isNullSender());
-        return isLocalDomain(maybeSender.get().getDomain());
+        return maybeSender.asOptional()
+            .map(MailAddress::getDomain)
+            .filter(this::isLocalDomain)
+            .isPresent();
     }
 
     /**
diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpIdentityVerificationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpIdentityVerificationTest.java
index f576aa8..f49abda 100644
--- a/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpIdentityVerificationTest.java
+++ b/server/mailet/integration-testing/src/test/java/org/apache/james/smtp/SmtpIdentityVerificationTest.java
@@ -22,6 +22,7 @@ package org.apache.james.smtp;
 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.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.io.File;
@@ -90,6 +91,42 @@ class SmtpIdentityVerificationTest {
     }
 
     @Test
+    void verifyIdentityShouldRejectNullSenderWHenAuthenticated(@TempDir File temporaryFolder) throws Exception {
+        createJamesServer(temporaryFolder, SmtpConfiguration.builder()
+            .requireAuthentication()
+            .verifyIdentity());
+
+        assertThatThrownBy(() ->
+            messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+                .authenticate(USER, PASSWORD)
+                .sendMessageNoSender(USER))
+            .isEqualTo(new SMTPSendingException(SmtpSendingStep.RCPT, "503 5.7.1 Incorrect Authentication for Specified Email Address\n"));
+    }
+
+    @Test
+    void verifyIdentityShouldAcceptNullSenderWhenNotAuthenticated(@TempDir File temporaryFolder) throws Exception {
+        createJamesServer(temporaryFolder, SmtpConfiguration.builder()
+            .verifyIdentity());
+
+        assertThatCode(() ->
+            messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+                .sendMessageNoSender(USER))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
+    void verifyIdentityShouldAcceptNullSenderWhenAuthenticationRequired(@TempDir File temporaryFolder) throws Exception {
+        createJamesServer(temporaryFolder, SmtpConfiguration.builder()
+            .requireAuthentication()
+            .verifyIdentity());
+
+        assertThatCode(() ->
+            messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort())
+                .sendMessageNoSender(USER))
+            .doesNotThrowAnyException();
+    }
+
+    @Test
     void rejectUnauthenticatedSendersUsingLocalDomains(@TempDir File temporaryFolder) throws Exception {
         createJamesServer(temporaryFolder, SmtpConfiguration.builder()
             .requireAuthentication()
diff --git a/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java b/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
index 655023b..d17c2c1 100644
--- a/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
+++ b/server/testing/src/main/java/org/apache/james/utils/SMTPMessageSender.java
@@ -126,6 +126,17 @@ public class SMTPMessageSender extends ExternalResource implements Closeable, Af
         return this;
     }
 
+    public SMTPMessageSender sendMessageNoSender(String recipient) throws IOException {
+        doHelo();
+        doSetSender("");
+        doAddRcpt(recipient);
+        doData("subject: test\r\n" +
+            "\r\n" +
+            "content\r\n" +
+            ".\r\n");
+        return this;
+    }
+
     public SMTPMessageSender sendMessage(Mail mail) throws MessagingException, IOException {
         String from = mail.getMaybeSender().asString();
         ImmutableList<String> recipients = mail.getRecipients().stream()

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


[james-project] 01/06: JAMES-3557 Changes collectors should be ordered

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 9fedbf751a479e90018ab402440104e49c83d48c
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 9 10:46:12 2021 +0700

    JAMES-3557 Changes collectors should be ordered
---
 .../src/main/java/org/apache/james/jmap/api/change/EmailChanges.java    | 2 +-
 .../src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java  | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
index 1376506..7cb78ab 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
@@ -69,7 +69,7 @@ public class EmailChanges {
 
             @Override
             public Set<Characteristics> characteristics() {
-                return Sets.immutableEnumSet(Characteristics.UNORDERED);
+                return ImmutableSet.of();
             }
         }
 
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
index c1af012..29522df 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
@@ -69,7 +69,7 @@ public class MailboxChanges {
 
             @Override
             public Set<Characteristics> characteristics() {
-                return Sets.immutableEnumSet(Characteristics.UNORDERED);
+                return ImmutableSet.of();
             }
         }
 

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


[james-project] 03/06: JAMES-3557 */changes: Fail explicitly when too much entries on a single change

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 50bd76cd3151f7e7bc0135384fdb484ca88e51a4
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 9 12:00:46 2021 +0700

    JAMES-3557 */changes: Fail explicitly when too much entries on a single change
---
 .../change/CanNotCalculateChangesException.java    |  26 +++++
 .../apache/james/jmap/api/change/EmailChanges.java |   4 +
 .../james/jmap/api/change/MailboxChanges.java      |   4 +
 .../api/change/EmailChangeRepositoryContract.java  |  27 +++--
 .../change/MailboxChangeRepositoryContract.java    |  11 ++-
 .../contract/EmailChangesMethodContract.scala      | 110 +++++++++++++++++++++
 .../james/jmap/method/EmailChangesMethod.scala     |   8 +-
 .../james/jmap/method/MailboxChangesMethod.scala   |   8 +-
 8 files changed, 173 insertions(+), 25 deletions(-)

diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/CanNotCalculateChangesException.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/CanNotCalculateChangesException.java
new file mode 100644
index 0000000..91bc2d0
--- /dev/null
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/CanNotCalculateChangesException.java
@@ -0,0 +1,26 @@
+/****************************************************************
+ * 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.change;
+
+public class CanNotCalculateChangesException extends RuntimeException {
+    public CanNotCalculateChangesException(String message) {
+        super(message);
+    }
+}
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
index 7cb78ab..807a058 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/EmailChanges.java
@@ -129,6 +129,10 @@ public class EmailChanges {
         }
 
         public EmailChanges build() {
+            if (hasMoreChanges && created.isEmpty() && updated.isEmpty() && destroyed.isEmpty()) {
+                throw new CanNotCalculateChangesException(String.format("Current change collector limit %d is exceeded by a single change, hence we cannot calculate changes.", limit.getValue()));
+            }
+
             return new EmailChanges(state, hasMoreChanges, created, updated, destroyed);
         }
     }
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
index 29522df..32a2160 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/change/MailboxChanges.java
@@ -133,6 +133,10 @@ public class MailboxChanges {
         }
 
         public MailboxChanges build() {
+            if (hasMoreChanges && created.isEmpty() && updated.isEmpty() && destroyed.isEmpty()) {
+                throw new CanNotCalculateChangesException(String.format("Current change collector limit %d is exceeded by a single change, hence we cannot calculate changes.", limit.getValue()));
+            }
+
             return new MailboxChanges(state, hasMoreChanges, isCountChangeOnly, created, updated, destroyed);
         }
 
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
index d72b4a4..d2a6641 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
@@ -445,7 +445,7 @@ public interface EmailChangeRepositoryContract {
     }
 
     @Test
-    default void getChangesShouldReturnEmptyWhenNumberOfChangesExceedMaxChanges() {
+    default void getChangesShoulThrowWhenNumberOfChangesExceedMaxChanges() {
         EmailChangeRepository repository = emailChangeRepository();
 
         State state = generateNewState();
@@ -470,18 +470,12 @@ public interface EmailChangeRepositoryContract {
             .isDelegated(false)
             .created(messageId2, messageId3)
             .build();
-        EmailChange change2 = EmailChange.builder()
-            .accountId(ACCOUNT_ID)
-            .state(generateNewState())
-            .date(DATE)
-            .isDelegated(false)
-            .created(messageId4, messageId5)
-            .build();
         repository.save(oldState).block();
         repository.save(change1).block();
 
-        assertThat(repository.getSinceState(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().getAllChanges())
-            .isEmpty();
+        assertThatThrownBy(() -> repository.getSinceState(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().getAllChanges())
+            .isInstanceOf(CanNotCalculateChangesException.class)
+            .hasMessage("Current change collector limit 1 is exceeded by a single change, hence we cannot calculate changes.");
     }
 
     @Test
@@ -552,13 +546,13 @@ public interface EmailChangeRepositoryContract {
             .state(generateNewState())
             .date(DATE)
             .isDelegated(false)
-            .updated(messageId2, messageId3)
+            .updated(messageId2, messageId1)
             .build();
         repository.save(oldState).block();
         repository.save(change1).block();
         repository.save(change2).block();
 
-        assertThat(repository.getSinceState(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().hasMoreChanges())
+        assertThat(repository.getSinceState(ACCOUNT_ID, state, Optional.of(Limit.of(2))).block().hasMoreChanges())
             .isTrue();
     }
 
@@ -1083,7 +1077,7 @@ public interface EmailChangeRepositoryContract {
     }
 
     @Test
-    default void getSinceStateWithDelegationShouldReturnEmptyWhenNumberOfChangesExceedMaxChanges() {
+    default void getSinceStateWithDelegationShouldThrowWhenNumberOfChangesExceedMaxChanges() {
         EmailChangeRepository repository = emailChangeRepository();
 
         State state = generateNewState();
@@ -1112,8 +1106,9 @@ public interface EmailChangeRepositoryContract {
         repository.save(oldState).block();
         repository.save(change1).block();
 
-        assertThat(repository.getSinceStateWithDelegation(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().getAllChanges())
-            .isEmpty();
+        assertThatThrownBy(() -> repository.getSinceStateWithDelegation(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().getAllChanges())
+            .isInstanceOf(CanNotCalculateChangesException.class)
+            .hasMessage("Current change collector limit 1 is exceeded by a single change, hence we cannot calculate changes.");
     }
 
     @Test
@@ -1182,7 +1177,7 @@ public interface EmailChangeRepositoryContract {
         repository.save(change1).block();
         repository.save(change2).block();
 
-        assertThat(repository.getSinceStateWithDelegation(ACCOUNT_ID, state, Optional.of(Limit.of(1))).block().hasMoreChanges())
+        assertThat(repository.getSinceStateWithDelegation(ACCOUNT_ID, state, Optional.of(Limit.of(2))).block().hasMoreChanges())
             .isTrue();
     }
 
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
index fc895a8..cd6ad4a 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
@@ -376,7 +376,7 @@ public interface MailboxChangeRepositoryContract {
     }
 
     @Test
-    default void getChangesShouldReturnEmptyWhenNumberOfChangesExceedMaxChanges() {
+    default void getChangesShouldReturnThrowWhenNumberOfChangesExceedMaxChanges() {
         MailboxChangeRepository repository = mailboxChangeRepository();
         State.Factory stateFactory = stateFactory();
         State referenceState = stateFactory.generate();
@@ -389,8 +389,9 @@ public interface MailboxChangeRepositoryContract {
         repository.save(oldState).block();
         repository.save(change1).block();
 
-        assertThat(repository.getSinceState(ACCOUNT_ID, referenceState, Optional.of(Limit.of(1))).block().getAllChanges())
-            .isEmpty();
+        assertThatThrownBy(() -> repository.getSinceState(ACCOUNT_ID, referenceState, Optional.of(Limit.of(1))).block().getAllChanges())
+            .isInstanceOf(CanNotCalculateChangesException.class)
+            .hasMessage("Current change collector limit 1 is exceeded by a single change, hence we cannot calculate changes.");
     }
 
     @Test
@@ -424,12 +425,12 @@ public interface MailboxChangeRepositoryContract {
         MailboxId id3 = generateNewMailboxId();
         MailboxChange oldState = MailboxChange.builder().accountId(ACCOUNT_ID).state(referenceState).date(DATE.minusHours(2)).isCountChange(false).created(ImmutableList.of(id1)).build();
         MailboxChange change1 = MailboxChange.builder().accountId(ACCOUNT_ID).state(stateFactory.generate()).date(DATE.minusHours(1)).isCountChange(false).created(ImmutableList.of(id2, id3)).build();
-        MailboxChange change2 = MailboxChange.builder().accountId(ACCOUNT_ID).state(stateFactory.generate()).date(DATE).isCountChange(false).updated(ImmutableList.of(id2, id3)).build();
+        MailboxChange change2 = MailboxChange.builder().accountId(ACCOUNT_ID).state(stateFactory.generate()).date(DATE).isCountChange(false).updated(ImmutableList.of(id2, id1)).build();
         repository.save(oldState).block();
         repository.save(change1).block();
         repository.save(change2).block();
 
-        assertThat(repository.getSinceState(ACCOUNT_ID, referenceState, Optional.of(Limit.of(1))).block().hasMoreChanges())
+        assertThat(repository.getSinceState(ACCOUNT_ID, referenceState, Optional.of(Limit.of(2))).block().hasMoreChanges())
             .isTrue();
     }
 
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesMethodContract.scala
index 80f7306..59222f7 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/EmailChangesMethodContract.scala
@@ -198,6 +198,116 @@ trait EmailChangesMethodContract {
   }
 
   @Test
+  def shouldFailWithCannotCalculateChangesWhenSingleChangeIsTooLarge(server: GuiceJamesServer): Unit = {
+    val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
+    val path: MailboxPath = MailboxPath.forUser(BOB, "mailbox1")
+
+    mailboxProbe.createMailbox(path)
+
+    val message: Message = Message.Builder
+      .of
+      .setSubject("test")
+      .setBody("testmail", StandardCharsets.UTF_8)
+      .build
+    val messageId1: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state1: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+    val messageId2: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state2: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+    val messageId3: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state3: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+    val messageId4: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state4: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+    val messageId5: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state5: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+    val messageId6: MessageId = mailboxProbe.appendMessage(BOB.asString(), path, AppendCommand.from(message)).getMessageId
+    val state6: State = waitForNextState(server, AccountId.fromUsername(BOB), State.INITIAL)
+
+    val updateEmail =
+      s"""{
+         |  "using": [
+         |    "urn:ietf:params:jmap:core",
+         |    "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [
+         |  ["Email/set",
+         |    {
+         |      "accountId": "$ACCOUNT_ID",
+         |      "update": {
+         |        "${messageId1.serialize}":{
+         |          "keywords/$$flagged": true
+         |        },
+         |        "${messageId2.serialize}":{
+         |          "keywords/$$flagged": true
+         |        },
+         |        "${messageId3.serialize}":{
+         |          "keywords/$$flagged": true
+         |        },
+         |        "${messageId4.serialize}":{
+         |          "keywords/$$flagged": true
+         |        },
+         |        "${messageId5.serialize}":{
+         |          "keywords/$$flagged": true
+         |        },
+         |        "${messageId6.serialize}":{
+         |          "keywords/$$flagged": true
+         |        }
+         |      }
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    `with`()
+      .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+      .body(updateEmail)
+      .post
+    .`then`
+      .statusCode(SC_OK)
+      .contentType(JSON)
+      .extract
+      .body
+      .asString
+
+    val request =
+      s"""{
+         |  "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"],
+         |  "methodCalls": [[
+         |    "Email/changes",
+         |    {
+         |      "accountId": "$ACCOUNT_ID",
+         |      "sinceState": "${state6.getValue}"
+         |    },
+         |    "c1"]]
+         |}""".stripMargin
+
+    awaitAtMostTenSeconds.untilAsserted { () =>
+      val response = `given`
+        .header(ACCEPT.toString, ACCEPT_RFC8621_VERSION_HEADER)
+        .body(request)
+      .when
+        .post
+      .`then`
+        .statusCode(SC_OK)
+        .contentType(JSON)
+        .extract
+        .body
+        .asString
+
+      assertThatJson(response)
+        .inPath("methodResponses[0]")
+        .isEqualTo(
+          s"""[
+             |  "error",
+             |  {
+             |    "type": "cannotCalculateChanges",
+             |    "description": "Current change collector limit 5 is exceeded by a single change, hence we cannot calculate changes."
+             |  },
+             |  "c1"
+             |]""".stripMargin)
+    }
+  }
+
+
+
+  @Test
   def shouldReturnUpdatedWhenMessageMove(server: GuiceJamesServer): Unit = {
     val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl])
     val path: MailboxPath = MailboxPath.forUser(BOB, "mailbox1")
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailChangesMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailChangesMethod.scala
index d33a3c6..d83525d 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailChangesMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/EmailChangesMethod.scala
@@ -21,11 +21,11 @@ package org.apache.james.jmap.method
 
 import eu.timepit.refined.auto._
 import javax.inject.Inject
-import org.apache.james.jmap.api.change.{EmailChangeRepository, EmailChanges, State => JavaState}
+import org.apache.james.jmap.api.change.{CanNotCalculateChangesException, EmailChangeRepository, EmailChanges, State => JavaState}
 import org.apache.james.jmap.api.model.{AccountId => JavaAccountId}
 import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JAMES_SHARES, JMAP_MAIL}
 import org.apache.james.jmap.core.Invocation.{Arguments, MethodName}
-import org.apache.james.jmap.core.{Invocation, State}
+import org.apache.james.jmap.core.{ErrorCode, Invocation, State}
 import org.apache.james.jmap.json.{EmailGetSerializer, ResponseSerializer}
 import org.apache.james.jmap.mail.{EmailChangesRequest, EmailChangesResponse, HasMoreChanges}
 import org.apache.james.jmap.routes.SessionSupplier
@@ -66,6 +66,10 @@ class EmailChangesMethod @Inject()(val metricFactory: MetricFactory,
           arguments = Arguments(EmailGetSerializer.serializeChanges(response)),
           methodCallId = invocation.invocation.methodCallId),
         processingContext = invocation.processingContext))
+      .onErrorResume {
+        case e: CanNotCalculateChangesException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.CannotCalculateChanges, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
+        case e => SMono.error(e)
+      }
 
   override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): Either[IllegalArgumentException, EmailChangesRequest] =
     EmailGetSerializer.deserializeEmailChangesRequest(invocation.arguments.value) match {
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
index d96361b..9f91b78 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxChangesMethod.scala
@@ -21,11 +21,11 @@ package org.apache.james.jmap.method
 
 import eu.timepit.refined.auto._
 import javax.inject.Inject
-import org.apache.james.jmap.api.change.{MailboxChangeRepository, MailboxChanges, State => JavaState}
+import org.apache.james.jmap.api.change.{CanNotCalculateChangesException, MailboxChangeRepository, MailboxChanges, State => JavaState}
 import org.apache.james.jmap.api.model.{AccountId => JavaAccountId}
 import org.apache.james.jmap.core.CapabilityIdentifier.{CapabilityIdentifier, JMAP_MAIL}
 import org.apache.james.jmap.core.Invocation.{Arguments, MethodName}
-import org.apache.james.jmap.core.{CapabilityIdentifier, Invocation, Properties, State}
+import org.apache.james.jmap.core.{CapabilityIdentifier, ErrorCode, Invocation, Properties, State}
 import org.apache.james.jmap.json.{MailboxSerializer, ResponseSerializer}
 import org.apache.james.jmap.mail.{HasMoreChanges, MailboxChangesRequest, MailboxChangesResponse}
 import org.apache.james.jmap.method.MailboxChangesMethod.updatedProperties
@@ -73,6 +73,10 @@ class MailboxChangesMethod @Inject()(mailboxSerializer: MailboxSerializer,
           arguments = Arguments(mailboxSerializer.serializeChanges(response)),
           methodCallId = invocation.invocation.methodCallId),
         processingContext = invocation.processingContext))
+      .onErrorResume {
+        case e: CanNotCalculateChangesException => SMono.just(InvocationWithContext(Invocation.error(ErrorCode.CannotCalculateChanges, e.getMessage, invocation.invocation.methodCallId), invocation.processingContext))
+        case e => SMono.error(e)
+      }
 
   override def getRequest(mailboxSession: MailboxSession, invocation: Invocation): Either[IllegalArgumentException, MailboxChangesRequest] =
     mailboxSerializer.deserializeMailboxChangesRequest(invocation.arguments.value) match {

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


[james-project] 04/06: JAMES-3557 JMAP */changes: Increase default maxChanges 5 -> 256

Posted by rc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0eed32519222fbf8097aec89f9c8d0ffa2bfe39f
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Apr 9 12:18:18 2021 +0700

    JAMES-3557 JMAP */changes: Increase default maxChanges 5 -> 256
    
    We rely on an injected constant to lower this value in our integration
    tests.
---
 .../james/modules/mailbox/CassandraMailboxModule.java  |  4 ++++
 .../james/modules/mailbox/MemoryMailboxModule.java     |  4 ++++
 .../change/CassandraEmailChangeRepository.java         | 15 +++++++++------
 .../change/CassandraMailboxChangeRepository.java       | 15 +++++++++------
 .../change/CassandraEmailChangeRepositoryTest.java     |  2 +-
 .../change/CassandraMailboxChangeRepositoryTest.java   |  3 +--
 .../memory/change/MemoryEmailChangeRepository.java     | 14 ++++++++++----
 .../memory/change/MemoryMailboxChangeRepository.java   | 18 ++++++++++++------
 .../jmap/api/change/EmailChangeRepositoryContract.java |  1 +
 .../api/change/MailboxChangeRepositoryContract.java    |  3 ++-
 .../memory/change/MemoryEmailChangeRepositoryTest.java |  3 ++-
 .../change/MemoryMailboxChangeRepositoryTest.java      |  4 ++--
 .../distributed/DistributedEmailChangeMethodTest.java  |  9 ++++++++-
 .../DistributedMailboxChangeMethodTest.java            |  9 ++++++++-
 .../rfc8621/memory/MemoryEmailChangesMethodTest.java   |  9 ++++++++-
 .../rfc8621/memory/MemoryMailboxChangesMethodTest.java |  9 ++++++++-
 .../james/jmap/change/MailboxChangeListenerTest.scala  |  9 +++++----
 17 files changed, 94 insertions(+), 37 deletions(-)

diff --git a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
index 0e8c809..01e47ca 100644
--- a/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
+++ b/server/container/guice/cassandra/src/main/java/org/apache/james/modules/mailbox/CassandraMailboxModule.java
@@ -30,6 +30,7 @@ import org.apache.james.eventsourcing.Event;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTO;
 import org.apache.james.eventsourcing.eventstore.cassandra.dto.EventDTOModule;
 import org.apache.james.jmap.api.change.EmailChangeRepository;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.MailboxChangeRepository;
 import org.apache.james.jmap.api.change.State;
 import org.apache.james.jmap.cassandra.change.CassandraEmailChangeRepository;
@@ -200,6 +201,9 @@ public class CassandraMailboxModule extends AbstractModule {
         bind(SessionProvider.class).to(SessionProviderImpl.class);
         bind(AttachmentContentLoader.class).to(AttachmentManager.class);
 
+        bind(Limit.class).annotatedWith(Names.named(CassandraEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(256));
+        bind(Limit.class).annotatedWith(Names.named(CassandraMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(256));
+
         bind(ReIndexer.class).to(ReIndexerImpl.class);
         bind(MessageIdReIndexer.class).to(MessageIdReIndexerImpl.class);
 
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
index 790af62..90c0e2a 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
@@ -27,6 +27,7 @@ import org.apache.james.adapter.mailbox.UserRepositoryAuthenticator;
 import org.apache.james.adapter.mailbox.UserRepositoryAuthorizator;
 import org.apache.james.events.EventListener;
 import org.apache.james.jmap.api.change.EmailChangeRepository;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.MailboxChangeRepository;
 import org.apache.james.jmap.api.change.State;
 import org.apache.james.jmap.memory.change.MemoryEmailChangeRepository;
@@ -140,6 +141,9 @@ public class MemoryMailboxModule extends AbstractModule {
         bind(MemoryDeletedMessageMetadataVault.class).in(Scopes.SINGLETON);
         bind(SessionProviderImpl.class).in(Scopes.SINGLETON);
 
+        bind(Limit.class).annotatedWith(Names.named(MemoryEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(256));
+        bind(Limit.class).annotatedWith(Names.named(MemoryMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(256));
+
         Multibinder.newSetBinder(binder(), MailboxManagerDefinition.class)
             .addBinding()
             .to(MemoryMailboxManagerDefinition.class);
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepository.java
index 59b1f77..deb4eba 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepository.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepository.java
@@ -22,6 +22,7 @@ package org.apache.james.jmap.cassandra.change;
 import java.util.Optional;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.apache.james.jmap.api.change.EmailChange;
 import org.apache.james.jmap.api.change.EmailChangeRepository;
@@ -37,13 +38,15 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraEmailChangeRepository implements EmailChangeRepository {
-    public static final Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
+    public static final String LIMIT_NAME = "emailChangeDefaultLimit";
 
     private final EmailChangeRepositoryDAO emailChangeRepositoryDAO;
+    private final Limit defaultLimit;
 
     @Inject
-    public CassandraEmailChangeRepository(EmailChangeRepositoryDAO emailChangeRepositoryDAO) {
+    public CassandraEmailChangeRepository(EmailChangeRepositoryDAO emailChangeRepositoryDAO, @Named(LIMIT_NAME) Limit defaultLimit) {
         this.emailChangeRepositoryDAO = emailChangeRepositoryDAO;
+        this.defaultLimit = defaultLimit;
     }
 
     @Override
@@ -60,14 +63,14 @@ public class CassandraEmailChangeRepository implements EmailChangeRepository {
         if (state.equals(State.INITIAL)) {
             return emailChangeRepositoryDAO.getAllChanges(accountId)
                 .filter(change -> !change.isDelegated())
-                .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return emailChangeRepositoryDAO.getChangesSince(accountId, state)
             .switchIfEmpty(Flux.error(new ChangeNotFoundException(state, String.format("State '%s' could not be found", state.getValue()))))
             .filter(change -> !change.isDelegated())
             .filter(change -> !change.getState().equals(state))
-            .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
@@ -78,13 +81,13 @@ public class CassandraEmailChangeRepository implements EmailChangeRepository {
 
         if (state.equals(State.INITIAL)) {
             return emailChangeRepositoryDAO.getAllChanges(accountId)
-                .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return emailChangeRepositoryDAO.getChangesSince(accountId, state)
             .switchIfEmpty(Flux.error(new ChangeNotFoundException(state, String.format("State '%s' could not be found", state.getValue()))))
             .filter(change -> !change.getState().equals(state))
-            .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new EmailChanges.Builder.EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
diff --git a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
index b0d9f05..ce2b5b9 100644
--- a/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
+++ b/server/data/data-jmap-cassandra/src/main/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepository.java
@@ -22,6 +22,7 @@ package org.apache.james.jmap.cassandra.change;
 import java.util.Optional;
 
 import javax.inject.Inject;
+import javax.inject.Named;
 
 import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.MailboxChange;
@@ -37,13 +38,15 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class CassandraMailboxChangeRepository implements MailboxChangeRepository {
-    public static final Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
+    public static final String LIMIT_NAME = "mailboxChangeDefaultLimit";
 
     private final MailboxChangeRepositoryDAO mailboxChangeRepositoryDAO;
+    private final Limit defaultLimit;
 
     @Inject
-    public CassandraMailboxChangeRepository(MailboxChangeRepositoryDAO mailboxChangeRepositoryDAO) {
+    public CassandraMailboxChangeRepository(MailboxChangeRepositoryDAO mailboxChangeRepositoryDAO, @Named(LIMIT_NAME) Limit defaultLimit) {
         this.mailboxChangeRepositoryDAO = mailboxChangeRepositoryDAO;
+        this.defaultLimit = defaultLimit;
     }
 
     @Override
@@ -60,14 +63,14 @@ public class CassandraMailboxChangeRepository implements MailboxChangeRepository
         if (state.equals(State.INITIAL)) {
             return mailboxChangeRepositoryDAO.getAllChanges(accountId)
                 .filter(change -> !change.isDelegated())
-                .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return mailboxChangeRepositoryDAO.getChangesSince(accountId, state)
             .switchIfEmpty(Flux.error(new ChangeNotFoundException(state, String.format("State '%s' could not be found", state.getValue()))))
             .filter(change -> !change.isDelegated())
             .filter(change -> !change.getState().equals(state))
-            .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
@@ -78,13 +81,13 @@ public class CassandraMailboxChangeRepository implements MailboxChangeRepository
 
         if (state.equals(State.INITIAL)) {
             return mailboxChangeRepositoryDAO.getAllChanges(accountId)
-                .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return mailboxChangeRepositoryDAO.getChangesSince(accountId, state)
             .switchIfEmpty(Flux.error(new ChangeNotFoundException(state, String.format("State '%s' could not be found", state.getValue()))))
             .filter(change -> !change.getState().equals(state))
-            .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new MailboxChanges.MailboxChangesBuilder.MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepositoryTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepositoryTest.java
index 8094155..5741f80 100644
--- a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepositoryTest.java
+++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraEmailChangeRepositoryTest.java
@@ -46,7 +46,7 @@ public class CassandraEmailChangeRepositoryTest implements EmailChangeRepository
     @BeforeEach
     public void setUp(CassandraCluster cassandra) {
         emailChangeRepositoryDAO = new EmailChangeRepositoryDAO(cassandra.getConf(), cassandra.getTypesProvider());
-        emailChangeRepository = new CassandraEmailChangeRepository(emailChangeRepositoryDAO);
+        emailChangeRepository = new CassandraEmailChangeRepository(emailChangeRepositoryDAO, DEFAULT_NUMBER_OF_CHANGES);
     }
 
     @Override
diff --git a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepositoryTest.java b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepositoryTest.java
index a6e743a..2c7e5e2 100644
--- a/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepositoryTest.java
+++ b/server/data/data-jmap-cassandra/src/test/java/org/apache/james/jmap/cassandra/change/CassandraMailboxChangeRepositoryTest.java
@@ -24,7 +24,6 @@ import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.components.CassandraModule;
 import org.apache.james.backends.cassandra.init.CassandraZonedDateTimeModule;
 import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionModule;
-import org.apache.james.jmap.api.change.MailboxChange;
 import org.apache.james.jmap.api.change.MailboxChangeRepository;
 import org.apache.james.jmap.api.change.MailboxChangeRepositoryContract;
 import org.apache.james.jmap.api.change.State;
@@ -47,7 +46,7 @@ public class CassandraMailboxChangeRepositoryTest implements MailboxChangeReposi
     @BeforeEach
     public void setUp(CassandraCluster cassandra) {
         mailboxChangeRepositoryDAO = new MailboxChangeRepositoryDAO(cassandra.getConf(), cassandra.getTypesProvider());
-        mailboxChangeRepository = new CassandraMailboxChangeRepository(mailboxChangeRepositoryDAO);
+        mailboxChangeRepository = new CassandraMailboxChangeRepository(mailboxChangeRepositoryDAO, DEFAULT_NUMBER_OF_CHANGES);
     }
 
     @Override
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepository.java
index 4f8ee2c..58d595b 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepository.java
@@ -22,6 +22,9 @@ package org.apache.james.jmap.memory.change;
 import java.util.Comparator;
 import java.util.Optional;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 import org.apache.james.jmap.api.change.EmailChange;
 import org.apache.james.jmap.api.change.EmailChangeRepository;
 import org.apache.james.jmap.api.change.EmailChanges;
@@ -40,11 +43,14 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class MemoryEmailChangeRepository implements EmailChangeRepository {
-    public static final Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
+    public static final String LIMIT_NAME = "emailChangeDefaultLimit";
 
     private final Multimap<AccountId, EmailChange> emailChangeMap;
+    private final Limit defaultLimit;
 
-    public MemoryEmailChangeRepository() {
+    @Inject
+    public MemoryEmailChangeRepository(@Named(LIMIT_NAME) Limit defaultLimit) {
+        this.defaultLimit = defaultLimit;
         this.emailChangeMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
     }
 
@@ -72,7 +78,7 @@ public class MemoryEmailChangeRepository implements EmailChangeRepository {
 
         return resolveAllChanges(accountId, state)
             .filter(change -> !change.isDelegated())
-            .collect(new EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
@@ -81,7 +87,7 @@ public class MemoryEmailChangeRepository implements EmailChangeRepository {
         Preconditions.checkNotNull(state);
 
         return resolveAllChanges(accountId, state)
-            .collect(new EmailChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new EmailChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
index efcc22a..b034b9b 100644
--- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
+++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepository.java
@@ -23,6 +23,9 @@ import java.util.Comparator;
 import java.util.Optional;
 import java.util.function.Predicate;
 
+import javax.inject.Inject;
+import javax.inject.Named;
+
 import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.MailboxChange;
 import org.apache.james.jmap.api.change.MailboxChangeRepository;
@@ -41,11 +44,14 @@ import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 
 public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
-    public static final Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
+    public static final String LIMIT_NAME = "mailboxChangeDefaultLimit";
 
     private final Multimap<AccountId, MailboxChange> mailboxChangeMap;
+    private final Limit defaultLimit;
 
-    public MemoryMailboxChangeRepository() {
+    @Inject
+    public MemoryMailboxChangeRepository(@Named(LIMIT_NAME) Limit defaultLimit) {
+        this.defaultLimit = defaultLimit;
         this.mailboxChangeMap = Multimaps.synchronizedListMultimap(ArrayListMultimap.create());
     }
 
@@ -63,7 +69,7 @@ public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
             return Flux.fromIterable(mailboxChangeMap.get(accountId))
                 .filter(Predicate.not(MailboxChange::isDelegated))
                 .sort(Comparator.comparing(MailboxChange::getDate))
-                .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return findByState(accountId, state)
@@ -71,7 +77,7 @@ public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
                 .filter(change -> change.getDate().isAfter(currentState.getDate()))
                 .filter(Predicate.not(MailboxChange::isDelegated))
                 .sort(Comparator.comparing(MailboxChange::getDate)))
-            .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     @Override
@@ -82,14 +88,14 @@ public class MemoryMailboxChangeRepository implements MailboxChangeRepository {
         if (state.equals(State.INITIAL)) {
             return Flux.fromIterable(mailboxChangeMap.get(accountId))
                 .sort(Comparator.comparing(MailboxChange::getDate))
-                .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+                .collect(new MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
         }
 
         return findByState(accountId, state)
             .flatMapMany(currentState -> Flux.fromIterable(mailboxChangeMap.get(accountId))
                 .filter(change -> change.getDate().isAfter(currentState.getDate()))
                 .sort(Comparator.comparing(MailboxChange::getDate)))
-            .collect(new MailboxChangeCollector(state, maxChanges.orElse(DEFAULT_NUMBER_OF_CHANGES)));
+            .collect(new MailboxChangeCollector(state, maxChanges.orElse(defaultLimit)));
     }
 
     private Mono<MailboxChange> findByState(AccountId accountId, State state) {
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
index d2a6641..7112ab6 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/EmailChangeRepositoryContract.java
@@ -34,6 +34,7 @@ import org.assertj.core.api.SoftAssertions;
 import org.junit.jupiter.api.Test;
 
 public interface EmailChangeRepositoryContract {
+    Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
     AccountId ACCOUNT_ID = AccountId.fromUsername(BOB);
     ZonedDateTime DATE = ZonedDateTime.now();
 
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
index cd6ad4a..57b4cf5 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/api/change/MailboxChangeRepositoryContract.java
@@ -38,6 +38,7 @@ import com.google.common.collect.ImmutableList;
 public interface MailboxChangeRepositoryContract {
     AccountId ACCOUNT_ID = AccountId.fromUsername(BOB);
     ZonedDateTime DATE = ZonedDateTime.now();
+    Limit DEFAULT_NUMBER_OF_CHANGES = Limit.of(5);
 
     State.Factory stateFactory();
 
@@ -376,7 +377,7 @@ public interface MailboxChangeRepositoryContract {
     }
 
     @Test
-    default void getChangesShouldReturnThrowWhenNumberOfChangesExceedMaxChanges() {
+    default void getChangesShouldThrowWhenNumberOfChangesExceedMaxChanges() {
         MailboxChangeRepository repository = mailboxChangeRepository();
         State.Factory stateFactory = stateFactory();
         State referenceState = stateFactory.generate();
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepositoryTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepositoryTest.java
index f7711db..84770f5 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepositoryTest.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryEmailChangeRepositoryTest.java
@@ -29,11 +29,12 @@ import org.apache.james.mailbox.model.TestMessageId;
 import org.junit.jupiter.api.BeforeEach;
 
 public class MemoryEmailChangeRepositoryTest implements EmailChangeRepositoryContract {
+
     EmailChangeRepository emailChangeRepository;
 
     @BeforeEach
     void setup() {
-        emailChangeRepository = new MemoryEmailChangeRepository();
+        emailChangeRepository = new MemoryEmailChangeRepository(DEFAULT_NUMBER_OF_CHANGES);
     }
 
     @Override
diff --git a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepositoryTest.java b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepositoryTest.java
index 660f18f..81a5245 100644
--- a/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepositoryTest.java
+++ b/server/data/data-jmap/src/test/java/org/apache/james/jmap/memory/change/MemoryMailboxChangeRepositoryTest.java
@@ -25,8 +25,8 @@ import org.apache.james.jmap.api.change.MailboxChangeRepository;
 import org.apache.james.jmap.api.change.MailboxChangeRepositoryContract;
 import org.apache.james.jmap.api.change.State;
 import org.apache.james.mailbox.model.MailboxId;
-import org.junit.jupiter.api.BeforeEach;
 import org.apache.james.mailbox.model.TestId;
+import org.junit.jupiter.api.BeforeEach;
 
 public class MemoryMailboxChangeRepositoryTest implements MailboxChangeRepositoryContract {
     MailboxChangeRepository mailboxChangeRepository;
@@ -35,7 +35,7 @@ public class MemoryMailboxChangeRepositoryTest implements MailboxChangeRepositor
 
     @BeforeEach
     void setup() {
-        mailboxChangeRepository = new MemoryMailboxChangeRepository();
+        mailboxChangeRepository = new MemoryMailboxChangeRepository(DEFAULT_NUMBER_OF_CHANGES);
         stateFactory = new State.DefaultFactory();
     }
 
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEmailChangeMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEmailChangeMethodTest.java
index d471d81..9d0c344 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEmailChangeMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedEmailChangeMethodTest.java
@@ -25,7 +25,10 @@ import org.apache.james.CassandraRabbitMQJamesServerMain;
 import org.apache.james.DockerElasticSearchExtension;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.State;
+import org.apache.james.jmap.cassandra.change.CassandraEmailChangeRepository;
+import org.apache.james.jmap.cassandra.change.CassandraMailboxChangeRepository;
 import org.apache.james.jmap.cassandra.change.CassandraStateFactory;
 import org.apache.james.jmap.rfc8621.contract.EmailChangesMethodContract;
 import org.apache.james.modules.AwsS3BlobStoreExtension;
@@ -34,6 +37,8 @@ import org.apache.james.modules.TestJMAPServerModule;
 import org.apache.james.modules.blobstore.BlobStoreConfiguration;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import com.google.inject.name.Names;
+
 public class DistributedEmailChangeMethodTest implements EmailChangesMethodContract {
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
@@ -50,7 +55,9 @@ public class DistributedEmailChangeMethodTest implements EmailChangesMethodContr
         .extension(new RabbitMQExtension())
         .extension(new AwsS3BlobStoreExtension())
         .server(configuration -> CassandraRabbitMQJamesServerMain.createServer(configuration)
-            .overrideWith(new TestJMAPServerModule()))
+            .overrideWith(new TestJMAPServerModule())
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(CassandraMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5)))
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(CassandraEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5))))
         .build();
 
     @Override
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedMailboxChangeMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedMailboxChangeMethodTest.java
index 76d5c5f..db65a99 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedMailboxChangeMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedMailboxChangeMethodTest.java
@@ -25,7 +25,10 @@ import org.apache.james.CassandraRabbitMQJamesServerMain;
 import org.apache.james.DockerElasticSearchExtension;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.State;
+import org.apache.james.jmap.cassandra.change.CassandraEmailChangeRepository;
+import org.apache.james.jmap.cassandra.change.CassandraMailboxChangeRepository;
 import org.apache.james.jmap.cassandra.change.CassandraStateFactory;
 import org.apache.james.jmap.rfc8621.contract.MailboxChangesMethodContract;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
@@ -36,6 +39,8 @@ import org.apache.james.modules.TestJMAPServerModule;
 import org.apache.james.modules.blobstore.BlobStoreConfiguration;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import com.google.inject.name.Names;
+
 public class DistributedMailboxChangeMethodTest implements MailboxChangesMethodContract {
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
@@ -52,7 +57,9 @@ public class DistributedMailboxChangeMethodTest implements MailboxChangesMethodC
         .extension(new RabbitMQExtension())
         .extension(new AwsS3BlobStoreExtension())
         .server(configuration -> CassandraRabbitMQJamesServerMain.createServer(configuration)
-            .overrideWith(new TestJMAPServerModule()))
+            .overrideWith(new TestJMAPServerModule())
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(CassandraMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5)))
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(CassandraEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5))))
         .build();
 
     @Override
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryEmailChangesMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryEmailChangesMethodTest.java
index 79634b0..d38dac6 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryEmailChangesMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryEmailChangesMethodTest.java
@@ -24,17 +24,24 @@ import static org.apache.james.MemoryJamesServerMain.IN_MEMORY_SERVER_AGGREGATE_
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.State;
+import org.apache.james.jmap.memory.change.MemoryEmailChangeRepository;
+import org.apache.james.jmap.memory.change.MemoryMailboxChangeRepository;
 import org.apache.james.jmap.rfc8621.contract.EmailChangesMethodContract;
 import org.apache.james.modules.TestJMAPServerModule;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import com.google.inject.name.Names;
+
 public class MemoryEmailChangesMethodTest implements EmailChangesMethodContract {
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder<>(JamesServerBuilder.defaultConfigurationProvider())
         .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
             .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
-            .overrideWith(new TestJMAPServerModule()))
+            .overrideWith(new TestJMAPServerModule())
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(MemoryMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5)))
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(MemoryEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5))))
         .build();
 
     @Override
diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
index e0cce3f..bf0f9a9 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
+++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryMailboxChangesMethodTest.java
@@ -26,20 +26,27 @@ import java.util.concurrent.ThreadLocalRandom;
 import org.apache.james.GuiceJamesServer;
 import org.apache.james.JamesServerBuilder;
 import org.apache.james.JamesServerExtension;
+import org.apache.james.jmap.api.change.Limit;
 import org.apache.james.jmap.api.change.State;
+import org.apache.james.jmap.memory.change.MemoryEmailChangeRepository;
+import org.apache.james.jmap.memory.change.MemoryMailboxChangeRepository;
 import org.apache.james.jmap.rfc8621.contract.MailboxChangesMethodContract;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.modules.TestJMAPServerModule;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import com.google.inject.name.Names;
+
 public class MemoryMailboxChangesMethodTest implements MailboxChangesMethodContract {
 
     @RegisterExtension
     static JamesServerExtension testExtension = new JamesServerBuilder<>(JamesServerBuilder.defaultConfigurationProvider())
         .server(configuration -> GuiceJamesServer.forConfiguration(configuration)
             .combineWith(IN_MEMORY_SERVER_AGGREGATE_MODULE)
-            .overrideWith(new TestJMAPServerModule()))
+            .overrideWith(new TestJMAPServerModule())
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(MemoryMailboxChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5)))
+            .overrideWith(binder -> binder.bind(Limit.class).annotatedWith(Names.named(MemoryEmailChangeRepository.LIMIT_NAME)).toInstance(Limit.of(5))))
         .build();
 
     @Override
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
index 23e5a2e..f4c0f7d 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/change/MailboxChangeListenerTest.scala
@@ -25,9 +25,9 @@ import java.util
 import javax.mail.Flags
 import org.apache.james.events.delivery.InVmEventDelivery
 import org.apache.james.events.{Event, EventBus, EventListener, Group, InVMEventBus, MemoryEventDeadLetters, Registration, RegistrationKey, RetryBackoffConfiguration}
-import org.apache.james.jmap.api.change.{EmailChange, EmailChangeRepository, MailboxChange, MailboxChangeRepository, State}
+import org.apache.james.jmap.api.change.{EmailChange, EmailChangeRepository, Limit, MailboxChange, MailboxChangeRepository, State}
 import org.apache.james.jmap.api.model.AccountId
-import org.apache.james.jmap.change.MailboxChangeListenerTest.ACCOUNT_ID
+import org.apache.james.jmap.change.MailboxChangeListenerTest.{ACCOUNT_ID, DEFAULT_NUMBER_OF_CHANGES}
 import org.apache.james.jmap.memory.change.{MemoryEmailChangeRepository, MemoryMailboxChangeRepository}
 import org.apache.james.mailbox.MessageManager.{AppendCommand, AppendResult, FlagsUpdateMode}
 import org.apache.james.mailbox.fixture.MailboxFixture.{ALICE, BOB}
@@ -45,6 +45,7 @@ import scala.jdk.OptionConverters._
 
 object MailboxChangeListenerTest {
   val ACCOUNT_ID = AccountId.fromUsername(BOB)
+  val DEFAULT_NUMBER_OF_CHANGES: Limit = Limit.of(5)
 }
 
 class MailboxChangeListenerTest {
@@ -71,9 +72,9 @@ class MailboxChangeListenerTest {
     mailboxManager = resources.getMailboxManager
     stateFactory = new State.DefaultFactory
     mailboxChangeFactory = new MailboxChange.Factory(stateFactory)
-    mailboxChangeRepository = new MemoryMailboxChangeRepository()
+    mailboxChangeRepository = new MemoryMailboxChangeRepository(DEFAULT_NUMBER_OF_CHANGES)
     emailChangeFactory = new EmailChange.Factory(stateFactory, resources.getMessageIdManager, resources.getMailboxManager)
-    emailChangeRepository = new MemoryEmailChangeRepository()
+    emailChangeRepository = new MemoryEmailChangeRepository(DEFAULT_NUMBER_OF_CHANGES)
     val eventBus = new EventBus {
       override def register(listener: EventListener.ReactiveEventListener, key: RegistrationKey): Publisher[Registration] = Mono.empty()
 

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