You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/07/01 05:07:49 UTC

[james-project] 03/03: JAMES-3212: handle subcrible/unsubcrible child's folder when update mailbox

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

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

commit bffdedf5e3c27a0e1861e377644f064b0c122493
Author: duc91 <du...@gmail.com>
AuthorDate: Tue Jun 16 16:57:26 2020 +0700

    JAMES-3212: handle subcrible/unsubcrible child's folder when update mailbox
---
 .../org/apache/james/mailbox/MailboxManager.java   |  58 +++++-
 .../apache/james/mailbox/MailboxManagerTest.java   | 197 +++++++++++++++++++++
 .../cassandra/CassandraMailboxManagerTest.java     |   7 +
 .../james/mailbox/jpa/JPAMailboxManagerTest.java   |   7 +
 .../DomainUserMaildirMailboxManagerTest.java       |  21 ++-
 .../maildir/FullUserMaildirMailboxManagerTest.java |  18 ++
 .../mailbox/inmemory/MemoryMailboxManagerTest.java |   7 +
 .../james/mailbox/store/MailboxReactorUtils.java   |   7 +-
 .../james/mailbox/store/StoreMailboxManager.java   | 149 ++++++++++------
 .../integration/SetMailboxesMethodTest.java        | 145 ++++++++++++++-
 .../draft/methods/SetMailboxesUpdateProcessor.java |  14 +-
 .../methods/SetMessagesCreationProcessor.java      |   2 +-
 .../methods/SetMailboxesUpdateProcessorTest.java   |   5 +-
 13 files changed, 553 insertions(+), 84 deletions(-)

diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
index ee859af..1b235bd 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MailboxManager.java
@@ -21,6 +21,7 @@ package org.apache.james.mailbox;
 
 import java.util.EnumSet;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 import org.apache.james.mailbox.exception.MailboxException;
@@ -163,6 +164,51 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      */
     Mailbox deleteMailbox(MailboxId mailboxId, MailboxSession session) throws MailboxException;
 
+    class MailboxRenamedResult {
+        private final MailboxId mailboxId;
+        private final MailboxPath originPath;
+        private final MailboxPath destinationPath;
+
+        public MailboxRenamedResult(MailboxId mailboxId, MailboxPath originPath, MailboxPath destinationPath) {
+            this.mailboxId = mailboxId;
+            this.originPath = originPath;
+            this.destinationPath = destinationPath;
+        }
+
+        public MailboxId getMailboxId() {
+            return mailboxId;
+        }
+
+        public MailboxPath getOriginPath() {
+            return originPath;
+        }
+
+        public MailboxPath getDestinationPath() {
+            return destinationPath;
+        }
+
+        @Override
+        public final boolean equals(Object o) {
+            if (o instanceof MailboxRenamedResult) {
+                MailboxRenamedResult that = (MailboxRenamedResult) o;
+
+                return Objects.equals(this.mailboxId, that.mailboxId)
+                    && Objects.equals(this.originPath, that.originPath)
+                    && Objects.equals(this.destinationPath, that.destinationPath);
+            }
+            return false;
+        }
+
+        @Override
+        public final int hashCode() {
+            return Objects.hash(mailboxId, originPath, destinationPath);
+        }
+    }
+
+    enum RenameOption {
+        NONE, RENAME_SUBSCRIPTIONS
+    }
+
     /**
      * Renames a mailbox.
      * 
@@ -179,7 +225,11 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      * @throws MailboxNotFoundException
      *            when the <code>from</code> mailbox does not exist
      */
-    void renameMailbox(MailboxPath from, MailboxPath to, MailboxSession session) throws MailboxException;
+    List<MailboxRenamedResult> renameMailbox(MailboxPath from, MailboxPath to, RenameOption option, MailboxSession session) throws MailboxException;
+
+    default List<MailboxRenamedResult> renameMailbox(MailboxPath from, MailboxPath to, MailboxSession session) throws MailboxException {
+        return renameMailbox(from, to, RenameOption.NONE, session);
+    }
 
     /**
      * Renames a mailbox.
@@ -197,7 +247,11 @@ public interface MailboxManager extends RequestAware, RightManager, MailboxAnnot
      * @throws MailboxNotFoundException
      *            when the <code>mailboxId</code> original mailbox does not exist
      */
-    void renameMailbox(MailboxId mailboxId, MailboxPath newMailboxPath, MailboxSession session) throws MailboxException;
+    List<MailboxRenamedResult> renameMailbox(MailboxId mailboxId, MailboxPath newMailboxPath, RenameOption option, MailboxSession session) throws MailboxException;
+
+    default List<MailboxRenamedResult> renameMailbox(MailboxId mailboxId, MailboxPath newMailboxPath, MailboxSession session) throws MailboxException {
+        return renameMailbox(mailboxId, newMailboxPath, RenameOption.NONE, session);
+    }
 
     /**
      * Copy the given {@link MessageRange} from one Mailbox to the other. 
diff --git a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
index 3d92d48..09069fe 100644
--- a/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
+++ b/mailbox/api/src/test/java/org/apache/james/mailbox/MailboxManagerTest.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.mailbox;
 
+import static org.apache.james.mailbox.MailboxManager.RenameOption.RENAME_SUBSCRIPTIONS;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
@@ -45,6 +46,7 @@ import org.apache.james.core.quota.QuotaCountUsage;
 import org.apache.james.core.quota.QuotaSizeLimit;
 import org.apache.james.core.quota.QuotaSizeUsage;
 import org.apache.james.mailbox.MailboxManager.MailboxCapabilities;
+import org.apache.james.mailbox.MailboxManager.MailboxRenamedResult;
 import org.apache.james.mailbox.MessageManager.AppendCommand;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
@@ -112,6 +114,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
     private static final int DEFAULT_MAXIMUM_LIMIT = 256;
 
     protected T mailboxManager;
+    private  SubscriptionManager subscriptionManager;
     private MailboxSession session;
     protected Message.Builder message;
 
@@ -120,6 +123,8 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
     protected abstract T provideMailboxManager();
 
+    protected abstract SubscriptionManager provideSubscriptionManager();
+
     protected abstract EventBus retrieveEventBus(T mailboxManager);
 
     protected Set<PreDeletionHook> preDeletionHooks() {
@@ -130,6 +135,7 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
     void setUp() throws Exception {
         setupMockForPreDeletionHooks();
         this.mailboxManager = provideMailboxManager();
+        this.subscriptionManager = provideSubscriptionManager();
 
         this.message = Message.Builder.of()
             .setSubject("test")
@@ -1533,6 +1539,197 @@ public abstract class MailboxManagerTest<T extends MailboxManager> {
 
     @Nested
     public class BasicFeaturesTests {
+
+        @Test
+        void renameMailboxShouldReturnAllRenamedResultsIncludeChildren() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx1.mbx2");
+            MailboxPath mailboxPath3 = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx3");
+            MailboxPath mailboxPath4 = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx3.mbx4");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx1.mbx9");
+
+            mailboxManager.createMailbox(mailboxPath1, session);
+            Optional<MailboxId> mailboxId2 = mailboxManager.createMailbox(mailboxPath2, session);
+            Optional<MailboxId> mailboxId3 = mailboxManager.createMailbox(mailboxPath3, session);
+            Optional<MailboxId> mailboxId4 = mailboxManager.createMailbox(mailboxPath4, session);
+
+            List<MailboxRenamedResult> mailboxRenamedResults = mailboxManager.renameMailbox(mailboxPath2, newMailboxPath, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                softly.assertThat(mailboxRenamedResults).hasSize(3);
+                softly.assertThat(mailboxRenamedResults).contains(
+                    new MailboxRenamedResult(mailboxId2.get(), mailboxPath2, MailboxPath.forUser(USER_1, "mbx1.mbx9")),
+                    new MailboxRenamedResult(mailboxId3.get(), mailboxPath3, MailboxPath.forUser(USER_1, "mbx1.mbx9.mbx3")),
+                    new MailboxRenamedResult(mailboxId4.get(), mailboxPath4, MailboxPath.forUser(USER_1, "mbx1.mbx9.mbx3.mbx4"))
+                );
+            });
+        }
+
+        @Test
+        void renameMailboxShouldReturnRenamedMailboxOnlyWhenNoChildren() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx1.mbx2");
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx3");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx9");
+
+            mailboxManager.createMailbox(mailboxPath1, session);
+            mailboxManager.createMailbox(mailboxPath2, session);
+            Optional<MailboxId> mailboxId3 = mailboxManager.createMailbox(originalPath, session);
+
+            List<MailboxRenamedResult> mailboxRenamedResults = mailboxManager.renameMailbox(originalPath, newMailboxPath, session);
+
+            SoftAssertions.assertSoftly(softly -> {
+                softly.assertThat(mailboxRenamedResults).hasSize(1);
+                softly.assertThat(mailboxRenamedResults).contains(
+                    new MailboxRenamedResult(mailboxId3.get(), originalPath, newMailboxPath)
+                );
+            });
+        }
+
+        @Test
+        void renameMailboxShouldRenamedChildMailboxesWithRenameOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx1.mbx2");
+            MailboxPath mailboxPath3 = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx3");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx9");
+
+            mailboxManager.createMailbox(originalPath, session);
+            mailboxManager.createMailbox(mailboxPath2, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+            subscriptionManager.subscribe(session, mailboxPath2.getName());
+
+            mailboxManager.createMailbox(mailboxPath3, session);
+            subscriptionManager.subscribe(session, mailboxPath3.getName());
+
+            mailboxManager.renameMailbox(originalPath, newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(
+                newMailboxPath.getName(),
+                "mbx9.mbx2",
+                "mbx9.mbx2.mbx3"
+            );
+        }
+
+        @Test
+        void renameMailboxShouldRenameSubscriptionWhenCalledWithRenameSubscriptionOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            mailboxManager.createMailbox(originalPath, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+
+            mailboxManager.renameMailbox(originalPath, newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(newMailboxPath.getName());
+        }
+
+        @Test
+        void renameMailboxShouldNotSubscribeUnsubscribedMailboxes() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            mailboxManager.createMailbox(originalPath, session);
+
+            mailboxManager.renameMailbox(originalPath, newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).isEmpty();
+        }
+
+        @Test
+        void renameMailboxShouldNotRenameSubscriptionWhenCalledWithoutRenameSubscriptionOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            mailboxManager.createMailbox(originalPath, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+
+            mailboxManager.renameMailbox(originalPath, newMailboxPath, MailboxManager.RenameOption.NONE, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(originalPath.getName());
+        }
+
+        @Test
+        void renameMailboxByIdShouldRenamedMailboxesWithRenameOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx1.mbx2");
+            MailboxPath mailboxPath3 = MailboxPath.forUser(USER_1, "mbx1.mbx2.mbx3");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx9");
+
+            Optional<MailboxId> id = mailboxManager.createMailbox(originalPath, session);
+            mailboxManager.createMailbox(mailboxPath2, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+            subscriptionManager.subscribe(session, mailboxPath2.getName());
+
+            mailboxManager.createMailbox(mailboxPath3, session);
+            subscriptionManager.subscribe(session, mailboxPath3.getName());
+
+            mailboxManager.renameMailbox(id.get(), newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(
+                newMailboxPath.getName(),
+                "mbx9.mbx2",
+                "mbx9.mbx2.mbx3"
+            );
+        }
+
+        @Test
+        void renameMailboxByIdShouldRenameSubscriptionWhenCalledWithRenameSubscriptionOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            Optional<MailboxId> id = mailboxManager.createMailbox(originalPath, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+
+            mailboxManager.renameMailbox(id.get(), newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(newMailboxPath.getName());
+        }
+
+        @Test
+        void renameMailboxByIdShouldNotSubscribeUnsubscribedMailboxes() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            Optional<MailboxId> id = mailboxManager.createMailbox(originalPath, session);
+
+            mailboxManager.renameMailbox(id.get(), newMailboxPath, RENAME_SUBSCRIPTIONS, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).isEmpty();
+        }
+
+        @Test
+        void renameMailboxByIdShouldNotRenameSubscriptionWhenCalledWithoutRenameSubscriptionOption() throws MailboxException {
+            MailboxSession session = mailboxManager.createSystemSession(USER_1);
+
+            MailboxPath originalPath = MailboxPath.forUser(USER_1, "mbx1");
+            MailboxPath newMailboxPath = MailboxPath.forUser(USER_1, "mbx2");
+
+            Optional<MailboxId> id = mailboxManager.createMailbox(originalPath, session);
+            subscriptionManager.subscribe(session, originalPath.getName());
+
+            mailboxManager.renameMailbox(id.get(), newMailboxPath, MailboxManager.RenameOption.NONE, session);
+
+            assertThat(subscriptionManager.subscriptions(session)).containsExactly(originalPath.getName());
+        }
+
         @Test
         void user1ShouldNotHaveAnInbox() throws Exception {
             session = mailboxManager.createSystemSession(USER_1);
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
index f57f28e..328fcc6 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/CassandraMailboxManagerTest.java
@@ -39,6 +39,7 @@ import org.apache.james.mailbox.MailboxManagerTest;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.MessageManager.AppendResult;
+import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.cassandra.ids.CassandraId;
 import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
 import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
@@ -65,6 +66,7 @@ import org.apache.james.mailbox.model.MessageAttachmentMetadata;
 import org.apache.james.mailbox.model.MessageRange;
 import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mailbox.store.PreDeletionHooks;
+import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.metrics.tests.RecordingMetricFactory;
 import org.apache.james.util.ClassLoaderUtils;
@@ -92,6 +94,11 @@ public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMai
     }
 
     @Override
+    protected SubscriptionManager provideSubscriptionManager() {
+        return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+    }
+
+    @Override
     protected EventBus retrieveEventBus(CassandraMailboxManager mailboxManager) {
         return mailboxManager.getEventBus();
     }
diff --git a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
index 4b917d9..530a596 100644
--- a/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
+++ b/mailbox/jpa/src/test/java/org/apache/james/mailbox/jpa/JPAMailboxManagerTest.java
@@ -22,8 +22,10 @@ import java.util.Optional;
 
 import org.apache.james.backends.jpa.JpaTestCluster;
 import org.apache.james.mailbox.MailboxManagerTest;
+import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.jpa.openjpa.OpenJPAMailboxManager;
+import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Nested;
@@ -48,6 +50,11 @@ class JPAMailboxManagerTest extends MailboxManagerTest<OpenJPAMailboxManager> {
         return openJPAMailboxManager.get();
     }
 
+    @Override
+    protected SubscriptionManager provideSubscriptionManager() {
+        return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+    }
+
     @AfterEach
     void tearDownJpa() {
         JPA_TEST_CLUSTER.clear(JPAMailboxFixture.MAILBOX_TABLE_NAMES);
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
index c54dd2c..601b019 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/DomainUserMaildirMailboxManagerTest.java
@@ -18,10 +18,14 @@
  ****************************************************************/
 package org.apache.james.mailbox.maildir;
 
+import java.util.Optional;
+
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
+import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.apache.james.mailbox.store.StoreSubscriptionManager;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
@@ -88,11 +92,24 @@ class DomainUserMaildirMailboxManagerTest extends MailboxManagerTest<StoreMailbo
 
     @RegisterExtension
     TemporaryFolderExtension temporaryFolder = new TemporaryFolderExtension();
-    
+    Optional<StoreMailboxManager> mailboxManager = Optional.empty();
+
     @Override
     protected StoreMailboxManager provideMailboxManager() {
+        if (!mailboxManager.isPresent()) {
+            mailboxManager = Optional.of(createMailboxManager());
+        }
+        return mailboxManager.get();
+    }
+
+    @Override
+    protected SubscriptionManager provideSubscriptionManager() {
+        return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+    }
+
+    private StoreMailboxManager createMailboxManager() {
         try {
-            return MaildirMailboxManagerProvider.createMailboxManager("/%domain/%user", temporaryFolder.getTemporaryFolder().getTempDir());
+            return MaildirMailboxManagerProvider.createMailboxManager("/%fulluser", temporaryFolder.getTemporaryFolder().getTempDir());
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
diff --git a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
index cb5d08f..e580662 100644
--- a/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
+++ b/mailbox/maildir/src/test/java/org/apache/james/mailbox/maildir/FullUserMaildirMailboxManagerTest.java
@@ -18,10 +18,15 @@
  ****************************************************************/
 package org.apache.james.mailbox.maildir;
 
+import java.util.Optional;
+
 import org.apache.james.junit.TemporaryFolderExtension;
 import org.apache.james.mailbox.MailboxManagerTest;
+import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.events.EventBus;
 import org.apache.james.mailbox.store.StoreMailboxManager;
+import org.apache.james.mailbox.store.StoreSubscriptionManager;
+import org.jetbrains.annotations.NotNull;
 import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.extension.RegisterExtension;
@@ -36,9 +41,22 @@ class FullUserMaildirMailboxManagerTest extends MailboxManagerTest<StoreMailboxM
 
     @RegisterExtension
     TemporaryFolderExtension temporaryFolder = new TemporaryFolderExtension();
+    Optional<StoreMailboxManager> mailboxManager = Optional.empty();
     
     @Override
     protected StoreMailboxManager provideMailboxManager() {
+        if (!mailboxManager.isPresent()) {
+            mailboxManager = Optional.of(createMailboxManager());
+        }
+        return mailboxManager.get();
+    }
+
+    @Override
+    protected SubscriptionManager provideSubscriptionManager() {
+        return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+    }
+
+    private StoreMailboxManager createMailboxManager() {
         try {
             return MaildirMailboxManagerProvider.createMailboxManager("/%fulluser", temporaryFolder.getTemporaryFolder().getTempDir());
         } catch (Exception e) {
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
index 7eb0846..c02c55f 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/MemoryMailboxManagerTest.java
@@ -20,7 +20,9 @@
 package org.apache.james.mailbox.inmemory;
 
 import org.apache.james.mailbox.MailboxManagerTest;
+import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.events.EventBus;
+import org.apache.james.mailbox.store.StoreSubscriptionManager;
 
 class MemoryMailboxManagerTest extends MailboxManagerTest<InMemoryMailboxManager> {
 
@@ -30,6 +32,11 @@ class MemoryMailboxManagerTest extends MailboxManagerTest<InMemoryMailboxManager
     }
 
     @Override
+    protected SubscriptionManager provideSubscriptionManager() {
+        return new StoreSubscriptionManager(provideMailboxManager().getMapperFactory());
+    }
+
+    @Override
     protected EventBus retrieveEventBus(InMemoryMailboxManager mailboxManager) {
         return mailboxManager.getEventBus();
     }
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MailboxReactorUtils.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MailboxReactorUtils.java
index c8e3cd3..0bfa8f8 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/MailboxReactorUtils.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/MailboxReactorUtils.java
@@ -22,6 +22,7 @@ package org.apache.james.mailbox.store;
 import java.util.Optional;
 
 import org.apache.james.mailbox.exception.MailboxException;
+import org.reactivestreams.Publisher;
 
 import reactor.core.publisher.Mono;
 
@@ -37,7 +38,11 @@ public abstract class MailboxReactorUtils {
             throw e;
         }
     }
-    
+
+    public static <T> T block(Publisher<T> publisher) throws MailboxException {
+        return block(Mono.from(publisher));
+    }
+
     public static <T> Optional<T> blockOptional(Mono<T> publisher) throws MailboxException {
         try {
             return publisher.blockOptional();
diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
index cab65d7..091e40b 100644
--- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
+++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMailboxManager.java
@@ -50,6 +50,7 @@ import org.apache.james.mailbox.exception.InsufficientRightsException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxExistsException;
 import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.exception.SubscriptionException;
 import org.apache.james.mailbox.exception.UnsupportedRightException;
 import org.apache.james.mailbox.extension.PreDeletionHook;
 import org.apache.james.mailbox.model.Mailbox;
@@ -82,6 +83,8 @@ import org.apache.james.mailbox.store.mail.model.impl.MessageParser;
 import org.apache.james.mailbox.store.quota.QuotaComponents;
 import org.apache.james.mailbox.store.search.MessageSearchIndex;
 import org.apache.james.mailbox.store.transaction.Mapper;
+import org.apache.james.mailbox.store.user.SubscriptionMapper;
+import org.apache.james.mailbox.store.user.model.Subscription;
 import org.apache.james.util.FunctionalUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -89,6 +92,7 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.github.steveash.guavate.Guavate;
 import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 
@@ -101,7 +105,6 @@ import reactor.core.publisher.Mono;
  * to extend just this class or use it directly.
  * <p/>
  * If you need a more low-level api just implement {@link MailboxManager} directly
- *
  */
 public class StoreMailboxManager implements MailboxManager {
     private static final Logger LOGGER = LoggerFactory.getLogger(StoreMailboxManager.class);
@@ -170,7 +173,7 @@ public class StoreMailboxManager implements MailboxManager {
     public EnumSet<MessageCapabilities> getSupportedMessageCapabilities() {
         return DEFAULT_NO_MESSAGE_CAPABILITIES;
     }
-    
+
     @Override
     public EnumSet<SearchCapabilities> getSupportedSearchCapabilities() {
         return index.getSupportedCapabilities(getSupportedMessageCapabilities());
@@ -248,14 +251,13 @@ public class StoreMailboxManager implements MailboxManager {
      */
     protected StoreMessageManager createMessageManager(Mailbox mailbox, MailboxSession session) throws MailboxException {
         return new StoreMessageManager(DEFAULT_NO_MESSAGE_CAPABILITIES, getMapperFactory(), getMessageSearchIndex(), getEventBus(),
-                getLocker(), mailbox, quotaManager,
+            getLocker(), mailbox, quotaManager,
             getQuotaComponents().getQuotaRootResolver(), configuration.getBatchSizes(),
             getStoreRightManager(), preDeletionHooks, new MessageStorer.WithoutAttachment(mailboxSessionMapperFactory, messageIdFactory, new MessageFactory.StoreMessageFactory()));
     }
 
     @Override
-    public MessageManager getMailbox(MailboxPath mailboxPath, MailboxSession session)
-            throws MailboxException {
+    public MessageManager getMailbox(MailboxPath mailboxPath, MailboxSession session) throws MailboxException {
         final MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
         Mailbox mailboxRow = mapper.findMailboxByPath(mailboxPath)
             .blockOptional()
@@ -275,8 +277,7 @@ public class StoreMailboxManager implements MailboxManager {
     }
 
     @Override
-    public MessageManager getMailbox(MailboxId mailboxId, MailboxSession session)
-            throws MailboxException {
+    public MessageManager getMailbox(MailboxId mailboxId, MailboxSession session) throws MailboxException {
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
         Mailbox mailboxRow = block(mapper.findMailboxById(mailboxId));
 
@@ -303,8 +304,7 @@ public class StoreMailboxManager implements MailboxManager {
     }
 
     @Override
-    public Optional<MailboxId> createMailbox(MailboxPath mailboxPath, MailboxSession mailboxSession)
-            throws MailboxException {
+    public Optional<MailboxId> createMailbox(MailboxPath mailboxPath, MailboxSession mailboxSession) throws MailboxException {
         LOGGER.debug("createMailbox {}", mailboxPath);
 
         assertMailboxPathBelongToUser(mailboxSession, mailboxPath);
@@ -343,7 +343,7 @@ public class StoreMailboxManager implements MailboxManager {
 
     private Stream<MailboxId> manageMailboxCreation(MailboxSession mailboxSession, boolean isRootPath, MailboxPath mailboxPath) throws MailboxException {
         if (mailboxPath.isInbox()) {
-            if (block(Mono.from(hasInbox(mailboxSession)))) {
+            if (block(hasInbox(mailboxSession))) {
                 return duplicatedINBOXCreation(isRootPath, mailboxPath);
             }
 
@@ -376,11 +376,11 @@ public class StoreMailboxManager implements MailboxManager {
                                 .flatMap(mailbox ->
                                     // notify listeners
                                     eventBus.dispatch(EventFactory.mailboxAdded()
-                                                    .randomEventId()
-                                                    .mailboxSession(mailboxSession)
-                                                    .mailbox(mailbox)
-                                                    .build(),
-                                            new MailboxIdRegistrationKey(mailbox.getMailboxId()))))));
+                                            .randomEventId()
+                                            .mailboxSession(mailboxSession)
+                                            .mailbox(mailbox)
+                                            .build(),
+                                        new MailboxIdRegistrationKey(mailbox.getMailboxId()))))));
                     } catch (Exception e) {
                         if (e instanceof MailboxExistsException) {
                             LOGGER.info("{} mailbox was created concurrently", mailboxPath.asString());
@@ -421,12 +421,12 @@ public class StoreMailboxManager implements MailboxManager {
         MailboxMapper mailboxMapper = mailboxSessionMapperFactory.getMailboxMapper(session);
 
         return mailboxMapper.execute(() -> block(mailboxMapper.findMailboxById(mailboxId)
-                .map(Throwing.<Mailbox, Mailbox>function(mailbox -> {
-                    assertIsOwner(session, mailbox.generateAssociatedPath());
-                    return mailbox;
-                }).sneakyThrow())
-                .flatMap(Throwing.<Mailbox, Mono<Mailbox>>function(mailbox ->
-                    doDeleteMailbox(mailboxMapper, mailbox, session)).sneakyThrow())));
+            .map(Throwing.<Mailbox, Mailbox>function(mailbox -> {
+                assertIsOwner(session, mailbox.generateAssociatedPath());
+                return mailbox;
+            }).sneakyThrow())
+            .flatMap(Throwing.<Mailbox, Mono<Mailbox>>function(mailbox ->
+                doDeleteMailbox(mailboxMapper, mailbox, session)).sneakyThrow())));
     }
 
     private Mono<Mailbox> doDeleteMailbox(MailboxMapper mailboxMapper, Mailbox mailbox, MailboxSession session) throws MailboxException {
@@ -447,14 +447,14 @@ public class StoreMailboxManager implements MailboxManager {
                 return preDeletionHooks.runHooks(PreDeletionHook.DeleteOperation.from(metadata))
                     .then(mailboxMapper.delete(mailbox))
                     .then(eventBus.dispatch(EventFactory.mailboxDeleted()
-                        .randomEventId()
-                        .mailboxSession(session)
-                        .mailbox(mailbox)
-                        .quotaRoot(quotaRoot)
-                        .quotaCount(QuotaCountUsage.count(messageCount))
-                        .quotaSize(QuotaSizeUsage.size(totalSize))
-                        .build(),
-                            new MailboxIdRegistrationKey(mailbox.getMailboxId())));
+                            .randomEventId()
+                            .mailboxSession(session)
+                            .mailbox(mailbox)
+                            .quotaRoot(quotaRoot)
+                            .quotaCount(QuotaCountUsage.count(messageCount))
+                            .quotaSize(QuotaSizeUsage.size(totalSize))
+                            .build(),
+                        new MailboxIdRegistrationKey(mailbox.getMailboxId())));
             })
             // We need to create a copy of the mailbox as maybe we can not refer to the real
             // mailbox once we remove it
@@ -462,7 +462,8 @@ public class StoreMailboxManager implements MailboxManager {
     }
 
     @Override
-    public void renameMailbox(MailboxPath from, MailboxPath to, MailboxSession session) throws MailboxException {
+    public List<MailboxRenamedResult> renameMailbox(MailboxPath from, MailboxPath to, RenameOption option,
+                                                    MailboxSession session) throws MailboxException {
         LOGGER.debug("renameMailbox {} to {}", from, to);
         MailboxPath sanitizedMailboxPath = to.sanitize(session.getPathDelimiter());
         validateDestinationPath(sanitizedMailboxPath, session);
@@ -470,26 +471,46 @@ public class StoreMailboxManager implements MailboxManager {
         assertIsOwner(session, from);
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
 
-        mapper.execute(Mapper.toTransaction(() -> {
+        return mapper.execute(() -> {
             Mailbox mailbox = blockOptional(mapper.findMailboxByPath(from))
                 .orElseThrow(() -> new MailboxNotFoundException(from));
-            doRenameMailbox(mailbox, sanitizedMailboxPath, session, mapper);
-        }));
+            return renameSubscriptionsIfNeeded(
+                doRenameMailbox(mailbox, sanitizedMailboxPath, session, mapper), option, session);
+        });
+    }
+
+    private List<MailboxRenamedResult> renameSubscriptionsIfNeeded(List<MailboxRenamedResult> renamedResults,
+                                                                   RenameOption option, MailboxSession session) throws SubscriptionException {
+        if (option == RenameOption.RENAME_SUBSCRIPTIONS) {
+            SubscriptionMapper subscriptionMapper = mailboxSessionMapperFactory.getSubscriptionMapper(session);
+            List<Subscription> subscriptionsForUser = subscriptionMapper.findSubscriptionsForUser(session.getUser());
+            renamedResults.forEach(Throwing.<MailboxRenamedResult>consumer(renamedResult -> {
+                Subscription subscription = new Subscription(session.getUser(), renamedResult.getOriginPath().getName());
+                if (subscriptionsForUser.contains(subscription)) {
+                    subscriptionMapper.delete(subscription);
+                    subscriptionMapper.save(new Subscription(session.getUser(), renamedResult.getDestinationPath().getName()));
+                }
+            }).sneakyThrow());
+        }
+        return renamedResults;
     }
 
     @Override
-    public void renameMailbox(MailboxId mailboxId, MailboxPath newMailboxPath, MailboxSession session) throws MailboxException {
+    public List<MailboxRenamedResult> renameMailbox(MailboxId mailboxId, MailboxPath newMailboxPath, RenameOption option,
+                                                    MailboxSession session) throws MailboxException {
         LOGGER.debug("renameMailbox {} to {}", mailboxId, newMailboxPath);
         MailboxPath sanitizedMailboxPath = newMailboxPath.sanitize(session.getPathDelimiter());
         validateDestinationPath(sanitizedMailboxPath, session);
 
         MailboxMapper mapper = mailboxSessionMapperFactory.getMailboxMapper(session);
 
-        mapper.execute(Mapper.toTransaction(() -> {
-            Mailbox mailbox = block(mapper.findMailboxById(mailboxId));
+        return mapper.execute(() -> {
+            Mailbox mailbox = mapper.findMailboxById(mailboxId).blockOptional()
+                .orElseThrow(() -> new MailboxNotFoundException(mailboxId));
             assertIsOwner(session, mailbox.generateAssociatedPath());
-            doRenameMailbox(mailbox, sanitizedMailboxPath, session, mapper);
-        }));
+            return renameSubscriptionsIfNeeded(
+                doRenameMailbox(mailbox, sanitizedMailboxPath, session, mapper), option, session);
+        });
     }
 
     private void validateDestinationPath(MailboxPath newMailboxPath, MailboxSession session) throws MailboxException {
@@ -507,21 +528,27 @@ public class StoreMailboxManager implements MailboxManager {
         }
     }
 
-    private void doRenameMailbox(Mailbox mailbox, MailboxPath newMailboxPath, MailboxSession session, MailboxMapper mapper) throws MailboxException {
+    private List<MailboxRenamedResult> doRenameMailbox(Mailbox mailbox, MailboxPath newMailboxPath, MailboxSession session, MailboxMapper mapper) throws MailboxException {
         // TODO put this into a serilizable transaction
 
+        ImmutableList.Builder<MailboxRenamedResult> resultBuilder = ImmutableList.builder();
+
         MailboxPath from = mailbox.generateAssociatedPath();
         mailbox.setNamespace(newMailboxPath.getNamespace());
         mailbox.setUser(newMailboxPath.getUser());
         mailbox.setName(newMailboxPath.getName());
+
         block(mapper.rename(mailbox)
-            .then(eventBus.dispatch(EventFactory.mailboxRenamed()
-                .randomEventId()
-                .mailboxSession(session)
-                .mailboxId(mailbox.getMailboxId())
-                .oldPath(from)
-                .newPath(newMailboxPath)
-                .build(),
+            .map(mailboxId -> {
+                resultBuilder.add(new MailboxRenamedResult(mailboxId, from, newMailboxPath));
+                return mailboxId;
+            }).then(eventBus.dispatch(EventFactory.mailboxRenamed()
+                    .randomEventId()
+                    .mailboxSession(session)
+                    .mailboxId(mailbox.getMailboxId())
+                    .oldPath(from)
+                    .newPath(newMailboxPath)
+                    .build(),
                 new MailboxIdRegistrationKey(mailbox.getMailboxId()))));
 
         // rename submailboxes
@@ -538,13 +565,16 @@ public class StoreMailboxManager implements MailboxManager {
                     MailboxPath fromPath = new MailboxPath(from, subOriginalName);
                     sub.setName(subNewName);
                     return mapper.rename(sub)
-                        .then(eventBus.dispatch(EventFactory.mailboxRenamed()
-                            .randomEventId()
-                            .mailboxSession(session)
-                            .mailboxId(sub.getMailboxId())
-                            .oldPath(fromPath)
-                            .newPath(sub.generateAssociatedPath())
-                            .build(),
+                        .map(mailboxId -> {
+                            resultBuilder.add(new MailboxRenamedResult(sub.getMailboxId(), fromPath, sub.generateAssociatedPath()));
+                            return mailboxId;
+                        }).then(eventBus.dispatch(EventFactory.mailboxRenamed()
+                                .randomEventId()
+                                .mailboxSession(session)
+                                .mailboxId(sub.getMailboxId())
+                                .oldPath(fromPath)
+                                .newPath(sub.generateAssociatedPath())
+                                .build(),
                             new MailboxIdRegistrationKey(sub.getMailboxId())))
                         .then(Mono.fromRunnable(() -> LOGGER.debug("Rename mailbox sub-mailbox {} to {}", subOriginalName, subNewName)));
                 })
@@ -553,6 +583,7 @@ public class StoreMailboxManager implements MailboxManager {
             return null;
 
         }, MailboxPathLocker.LockType.Write);
+        return resultBuilder.build();
     }
 
     @Override
@@ -571,7 +602,7 @@ public class StoreMailboxManager implements MailboxManager {
         return copyMessages(set, session, toMailbox, fromMailbox);
     }
 
-    
+
     private List<MessageRange> copyMessages(MessageRange set, MailboxSession session, StoreMessageManager toMailbox, StoreMessageManager fromMailbox) throws MailboxException {
         return configuration.getCopyBatcher().batchMessages(set,
             messageRange -> fromMailbox.copyTo(messageRange, toMailbox, session));
@@ -673,7 +704,7 @@ public class StoreMailboxManager implements MailboxManager {
 
 
     private Flux<MailboxId> getInMailboxes(ImmutableSet<MailboxId> inMailboxes, MailboxSession session) throws MailboxException {
-       if (inMailboxes.isEmpty()) {
+        if (inMailboxes.isEmpty()) {
             return getAllReadableMailbox(session);
         } else {
             return filterReadable(inMailboxes, session);
@@ -782,13 +813,13 @@ public class StoreMailboxManager implements MailboxManager {
 
     @Override
     public List<MailboxAnnotation> getAnnotationsByKeys(MailboxPath mailboxPath, MailboxSession session, Set<MailboxAnnotationKey> keys)
-            throws MailboxException {
+        throws MailboxException {
         return annotationManager.getAnnotationsByKeys(mailboxPath, session, keys);
     }
 
     @Override
     public void updateAnnotations(MailboxPath mailboxPath, MailboxSession session, List<MailboxAnnotation> mailboxAnnotations)
-            throws MailboxException {
+        throws MailboxException {
         annotationManager.updateAnnotations(mailboxPath, session, mailboxAnnotations);
     }
 
@@ -800,13 +831,13 @@ public class StoreMailboxManager implements MailboxManager {
 
     @Override
     public List<MailboxAnnotation> getAnnotationsByKeysWithOneDepth(MailboxPath mailboxPath, MailboxSession session,
-            Set<MailboxAnnotationKey> keys) throws MailboxException {
+                                                                    Set<MailboxAnnotationKey> keys) throws MailboxException {
         return annotationManager.getAnnotationsByKeysWithOneDepth(mailboxPath, session, keys);
     }
 
     @Override
     public List<MailboxAnnotation> getAnnotationsByKeysWithAllDepth(MailboxPath mailboxPath, MailboxSession session,
-            Set<MailboxAnnotationKey> keys) throws MailboxException {
+                                                                    Set<MailboxAnnotationKey> keys) throws MailboxException {
         return annotationManager.getAnnotationsByKeysWithAllDepth(mailboxPath, session, keys);
     }
 
diff --git a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMailboxesMethodTest.java b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMailboxesMethodTest.java
index 2d9e3d0..86a9586 100644
--- a/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMailboxesMethodTest.java
+++ b/server/protocols/jmap-draft-integration-testing/jmap-draft-integration-testing-common/src/test/java/org/apache/james/jmap/draft/methods/integration/SetMailboxesMethodTest.java
@@ -21,6 +21,7 @@ package org.apache.james.jmap.draft.methods.integration;
 
 import static io.restassured.RestAssured.given;
 import static io.restassured.RestAssured.with;
+import static io.restassured.http.ContentType.JSON;
 import static org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser;
 import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS;
 import static org.apache.james.jmap.JMAPTestingConstants.DOMAIN;
@@ -74,6 +75,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
 import io.restassured.RestAssured;
+import io.restassured.response.Response;
 
 public abstract class SetMailboxesMethodTest {
 
@@ -81,7 +83,7 @@ public abstract class SetMailboxesMethodTest {
     private static final String WRITE = String.valueOf(Right.Write.asCharacter());
     private static final String DELETE_MESSAGES = String.valueOf(Right.DeleteMessages.asCharacter());
 
-    private static int MAILBOX_NAME_LENGTH_64K = 65536;
+    private static final int MAILBOX_NAME_LENGTH_64K = 65536;
 
     protected abstract GuiceJamesServer createJmapServer() throws IOException;
 
@@ -338,17 +340,15 @@ public abstract class SetMailboxesMethodTest {
 
     @Test
     public void subscriptionUserShouldBeChangedWhenUpdateMailbox() throws Exception {
-        mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username.asString(), "root");
-
-        String initialMailboxName = "root.myBox";
-        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username.asString(), initialMailboxName);
+        String initialMailboxName = "myBox";
+        String mailboxId = createMailBoxThroughJMAP(initialMailboxName);
 
         String requestBody =
             "[" +
                 "  [ \"setMailboxes\"," +
                 "    {" +
                 "      \"update\": {" +
-                "        \"" + mailboxId.serialize() + "\" : {" +
+                "        \"" + mailboxId + "\" : {" +
                 "          \"name\" : \"mySecondBox\"" +
                 "        }" +
                 "      }" +
@@ -367,6 +367,139 @@ public abstract class SetMailboxesMethodTest {
     }
 
     @Test
+    public void subscriptionUserShouldBeChangedWhenUpdateParentMailbox() throws Exception {
+        MailboxId parentId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username.asString(), "root");
+
+        String secondMailboxName = "second";
+        String secondMailboxId = createSubMailBox(parentId.serialize(), secondMailboxName);
+
+        String thirdMailBoxName = "third";
+        String thirdMailboxId = createSubMailBox(secondMailboxId, thirdMailBoxName);
+
+        String fourthMailboxName = "fourth";
+        createSubMailBox(thirdMailboxId, fourthMailboxName);
+
+        String requestBody =
+            "[" +
+                "  [ \"setMailboxes\"," +
+                "    {" +
+                "      \"update\": {" +
+                "        \"" + thirdMailboxId + "\" : {" +
+                "          \"name\" : \"thirdtest\" ,"  +
+                "          \"parentId\" : \"" + secondMailboxId + "\""  +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+        with()
+            .header("Authorization", accessToken.asString())
+            .body(requestBody)
+            .post("/jmap");
+
+        assertThat(mailboxProbe.listSubscriptions(username.asString()))
+            .contains("root.second.thirdtest.fourth")
+            .doesNotContain("root.second.third.fourth");
+    }
+
+    @Test
+    public void subscriptionUserShouldBeChangedForAllChildrenWhenUpdateParentMailbox() throws Exception {
+        MailboxId parentId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, username.asString(), "root");
+
+        String secondMailboxName = "second";
+        String secondMailboxId = createSubMailBox(parentId.serialize(), secondMailboxName);
+
+        String thirdMailBoxName = "third";
+        String thirdMailboxId = createSubMailBox(secondMailboxId, thirdMailBoxName);
+
+        String fourthMailboxName = "fourth";
+        createSubMailBox(thirdMailboxId, fourthMailboxName);
+
+        String requestBody =
+            "[" +
+                "  [ \"setMailboxes\"," +
+                "    {" +
+                "      \"update\": {" +
+                "        \"" + secondMailboxId + "\" : {" +
+                "          \"name\" : \"secondtest\" ,"  +
+                "          \"parentId\" : \"" + parentId.serialize() + "\""  +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+        with()
+            .header("Authorization", accessToken.asString())
+            .body(requestBody)
+            .post("/jmap");
+
+        assertThat(mailboxProbe.listSubscriptions(username.asString()))
+            .contains("root.secondtest.third.fourth")
+            .doesNotContain("root.second.third.fourth");
+    }
+
+    private String createSubMailBox(String parentMailboxId, String childMailboxName) {
+        String clientIdentifier = "whatever";
+        String createChildMailbox =
+            "[" +
+                "  [ \"setMailboxes\"," +
+                "    {" +
+                "      \"create\": {" +
+                "        \"" + clientIdentifier + "\" : {" +
+                "          \"name\" : \"" + childMailboxName + "\"," +
+                "          \"parentId\" : \"" + parentMailboxId + "\"" +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+
+        Response response = given()
+            .header("Authorization", accessToken.asString())
+            .body(createChildMailbox)
+        .when()
+            .post("/jmap")
+        .then()
+            .contentType(JSON)
+        .extract()
+            .response();
+
+        return response.jsonPath().get("[0][1].created." + clientIdentifier + ".id");
+    }
+
+    private String createMailBoxThroughJMAP(String mailboxName) {
+        String clientIdentifier = "whatever";
+        String createMailbox =
+            "[" +
+                "  [ \"setMailboxes\"," +
+                "    {" +
+                "      \"create\": {" +
+                "        \"" + clientIdentifier + "\" : {" +
+                "          \"name\" : \"" + mailboxName + "\"" +
+                "        }" +
+                "      }" +
+                "    }," +
+                "    \"#0\"" +
+                "  ]" +
+                "]";
+
+        Response response = given()
+            .header("Authorization", accessToken.asString())
+            .body(createMailbox)
+        .when()
+            .post("/jmap")
+        .then()
+            .contentType(JSON)
+        .extract()
+            .response();
+
+        return response.jsonPath().get("[0][1].created." + clientIdentifier + ".id");
+    }
+
+    @Test
     public void subscriptionUserShouldBeChangedWhenCreateThenUpdateMailboxNameWithJMAP() throws Exception {
         String requestBody =
             "[" +
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
index b64d8d8..1d79ceb 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessor.java
@@ -41,7 +41,6 @@ import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.Role;
-import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.exception.DifferentDomainException;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.exception.MailboxExistsException;
@@ -70,14 +69,12 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
     private final MailboxManager mailboxManager;
     private final MailboxFactory mailboxFactory;
     private final MetricFactory metricFactory;
-    private final SubscriptionManager subscriptionManager;
 
     @Inject
     @VisibleForTesting
-    SetMailboxesUpdateProcessor(MailboxUtils mailboxUtils, MailboxManager mailboxManager, SubscriptionManager subscriptionManager, MailboxFactory mailboxFactory, MetricFactory metricFactory) {
+    SetMailboxesUpdateProcessor(MailboxUtils mailboxUtils, MailboxManager mailboxManager, MailboxFactory mailboxFactory, MetricFactory metricFactory) {
         this.mailboxUtils = mailboxUtils;
         this.mailboxManager = mailboxManager;
-        this.subscriptionManager = subscriptionManager;
         this.mailboxFactory = mailboxFactory;
         this.metricFactory = metricFactory;
     }
@@ -156,7 +153,7 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
                     .description("An error occurred when updating the mailbox")
                     .build());
         }
-   }
+    }
 
     private void assertNotSharedOutboxOrDraftMailbox(Mailbox mailbox, MailboxUpdateRequest updateRequest) {
         Preconditions.checkArgument(!updateRequest.getSharedWith().isPresent() || !mailbox.hasRole(Role.OUTBOX), "Sharing 'Outbox' is forbidden");
@@ -258,6 +255,7 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
     private void updateMailbox(Mailbox mailbox, MailboxUpdateRequest updateRequest, MailboxSession mailboxSession) throws MailboxException {
         MailboxPath originMailboxPath = mailboxManager.getMailbox(mailbox.getId(), mailboxSession).getMailboxPath();
         MailboxPath destinationMailboxPath = computeNewMailboxPath(mailbox, originMailboxPath, updateRequest, mailboxSession);
+
         if (updateRequest.getSharedWith().isPresent()) {
             mailboxManager.setRights(mailbox.getId(),
                 updateRequest.getSharedWith()
@@ -266,11 +264,9 @@ public class SetMailboxesUpdateProcessor implements SetMailboxesProcessor {
                     .toMailboxAcl(),
                 mailboxSession);
         }
-        if (!originMailboxPath.equals(destinationMailboxPath)) {
-            mailboxManager.renameMailbox(mailbox.getId(), destinationMailboxPath, mailboxSession);
 
-            subscriptionManager.unsubscribe(mailboxSession, originMailboxPath.getName());
-            subscriptionManager.subscribe(mailboxSession, destinationMailboxPath.getName());
+        if (!originMailboxPath.equals(destinationMailboxPath)) {
+            mailboxManager.renameMailbox(mailbox.getId(), destinationMailboxPath, MailboxManager.RenameOption.RENAME_SUBSCRIPTIONS, mailboxSession);
         }
     }
 
diff --git a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
index a384bd8..9936468 100644
--- a/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
+++ b/server/protocols/jmap-draft/src/main/java/org/apache/james/jmap/draft/methods/SetMessagesCreationProcessor.java
@@ -221,7 +221,7 @@ public class SetMessagesCreationProcessor implements SetMessagesProcessor {
     }
 
     private void performCreate(CreationMessageEntry entry, Builder responseBuilder, MailboxSession session)
-        throws MailboxException, InvalidMailboxForCreationException, MessagingException, AttachmentsNotFoundException, IOException {
+        throws MailboxException, MessagingException, AttachmentsNotFoundException, IOException {
 
         if (isAppendToMailboxWithRole(Role.OUTBOX, entry.getValue(), session)) {
             sendMailViaOutbox(entry, responseBuilder, session);
diff --git a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
index 34cc705..79859c4 100644
--- a/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
+++ b/server/protocols/jmap-draft/src/test/java/org/apache/james/jmap/draft/methods/SetMailboxesUpdateProcessorTest.java
@@ -37,7 +37,6 @@ import org.apache.james.jmap.draft.utils.MailboxUtils;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
-import org.apache.james.mailbox.SubscriptionManager;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.inmemory.InMemoryId;
 import org.apache.james.metrics.api.MetricFactory;
@@ -49,7 +48,6 @@ import org.mockito.Mockito;
 public class SetMailboxesUpdateProcessorTest {
 
     private MailboxManager mockedMailboxManager;
-    private SubscriptionManager mockSubscriptionManager;
     private MailboxUtils mockedMailboxUtils;
     private MailboxFactory mockedMailboxFactory;
     private MailboxSession mockedMailboxSession;
@@ -58,12 +56,11 @@ public class SetMailboxesUpdateProcessorTest {
     @Before
     public void setup() {
         mockedMailboxManager = mock(MailboxManager.class);
-        mockSubscriptionManager = mock(SubscriptionManager.class);
         mockedMailboxUtils = mock(MailboxUtils.class);
         mockedMailboxFactory = mock(MailboxFactory.class);
         mockedMailboxSession = mock(MailboxSession.class);
         MetricFactory metricFactory = new RecordingMetricFactory();
-        sut = new SetMailboxesUpdateProcessor(mockedMailboxUtils, mockedMailboxManager, mockSubscriptionManager, mockedMailboxFactory, metricFactory);
+        sut = new SetMailboxesUpdateProcessor(mockedMailboxUtils, mockedMailboxManager, mockedMailboxFactory, metricFactory);
     }
 
     @Test


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