(geronimo-mail) branch main updated: GERONIMO-6891 Fix IMAPFolder.renameTo reporting failure after a successful rename

[email protected] Sat, 18 Jul 2026 08:53:48 +0000
Newsgroups gmane.comp.java.geronimo.cvs
Message-ID <178436482805.1665753.2283580097426125762@gitbox3-he-fi.apache.org>
This is an automated email from the ASF dual-hosted git repository.

rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/geronimo-mail.git


The following commit(s) were added to refs/heads/main by this push:
     new 7b72cd3  GERONIMO-6891 Fix IMAPFolder.renameTo reporting failure after a successful rename
7b72cd3 is described below

commit 7b72cd3b6463b3d4b30fa684abcd84fdd6b7e126
Author: Richard Zowalla <[email protected]>
AuthorDate: Sat Jul 18 10:53:27 2026 +0200

    GERONIMO-6891
    Fix IMAPFolder.renameTo reporting failure after a successful rename
---
 .../geronimo/mail/store/imap/IMAPFolder.java       |  11 +-
 .../mail/store/imap/IMAPFolderRenameTest.java      | 128 +++++++++++++++++++++
 .../geronimo/mail/testserver/MailServer.java       |  21 ++++
 geronimo-mail_2.1_tck/src/tck/geronimo.jtx         | 102 +---------------
 4 files changed, 161 insertions(+), 101 deletions(-)

diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
index 779ff85..f228d24 100644
--- a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/main/java/org/apache/geronimo/mail/store/imap/IMAPFolder.java
@@ -587,12 +587,15 @@ public class IMAPFolder extends Folder implements UIDFolder, IMAPUntaggedRespons
 
         IMAPConnection connection = getConnection();
         try {
-            // delete this one now.
+            // rename this one now.
             connection.renameMailbox(fullname, f.getFullName());
-            // we renamed, so get a fresh set of status
-            refreshStatus(false);
+            // a folder with our old name no longer exists on the server, so
+            // any cached state is stale now.  Do NOT query the server using the
+            // old name (e.g. via refreshStatus()) -- that would fail.
+            cachedStatus = null;
+            listInfo = null;
 
-            // notify interested parties about the deletion.
+            // notify interested parties about the rename.
             notifyFolderRenamedListeners(f);
             return true;
         } catch (MessagingException e) {
diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPFolderRenameTest.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPFolderRenameTest.java
new file mode 100644
index 0000000..bd7ba08
--- /dev/null
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/store/imap/IMAPFolderRenameTest.java
@@ -0,0 +1,128 @@
+/**
+ *  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.geronimo.mail.store.imap;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.util.Properties;
+
+import jakarta.mail.Folder;
+import jakarta.mail.Session;
+import jakarta.mail.Store;
+
+import org.apache.geronimo.mail.testserver.AbstractProtocolTest;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Regression test for IMAPFolder.renameTo against Apache James.
+ *
+ * renameTo used to refresh the folder status with a STATUS command issued
+ * under the OLD mailbox name right after a successful server-side RENAME.
+ * James answers that STATUS with a tagged NO ("Mailbox not found"), the
+ * resulting CommandFailedException was swallowed and renameTo returned
+ * false even though the mailbox had really been renamed.  In the Jakarta
+ * Mail TCK this left the shared "test1" mailbox renamed for the remainder
+ * of the run, making ~90 subsequent tests fail with CommandFailedException
+ * when opening "test1" (SELECT/EXAMINE answered with "NO ... No such
+ * mailbox.").
+ */
+public class IMAPFolderRenameTest extends AbstractProtocolTest {
+
+    private Store connect() throws Exception {
+        final Properties props = new Properties();
+        props.setProperty("mail.imap.port", String.valueOf(imapConf.getListenerPort()));
+        props.setProperty("mail.debug", "true");
+        final Session session = Session.getInstance(props);
+        final Store store = session.getStore("imap");
+        store.connect("127.0.0.1", "serveruser", "serverpass");
+        return store;
+    }
+
+    private void createMailboxWithMessage(final String name) throws Exception {
+        server.createUserMailbox(name);
+        final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+        try (InputStream in = IMAPFolderRenameTest.class.getResourceAsStream("/messages/simple.msg")) {
+            final byte[] buf = new byte[4096];
+            int n;
+            while ((n = in.read(buf)) != -1) {
+                bout.write(buf, 0, n);
+            }
+        }
+        server.appendToUserMailbox(name, bout.toByteArray());
+    }
+
+    /**
+     * A successful server-side RENAME must be reported as success by
+     * renameTo, and the folder must remain usable under the new name.
+     */
+    @Test
+    public void testRenameToReportsSuccess() throws Exception {
+        start();
+        createMailboxWithMessage("test1");
+
+        final Store store = connect();
+        try {
+            final Folder test1 = store.getDefaultFolder().getFolder("test1");
+            final Folder test2 = store.getDefaultFolder().getFolder("test2");
+
+            assertTrue(test1.renameTo(test2), "renameTo must return true for a successful server-side RENAME");
+            assertTrue(test2.exists(), "renamed mailbox must exist under the new name");
+            assertFalse(test1.exists(), "renamed mailbox must no longer exist under the old name");
+        } finally {
+            store.close();
+        }
+    }
+
+    /**
+     * The TCK pattern (Folder/renameTo_Test): rename away, then rename back,
+     * then open the folder again.  Before the fix the rename-back never
+     * happened (renameTo wrongly returned false) and every subsequent open
+     * of the folder failed with CommandFailedException.
+     */
+    @Test
+    public void testOpenAfterRenameAndRenameBack() throws Exception {
+        start();
+        createMailboxWithMessage("test1");
+
+        final Store store = connect();
+        try {
+            final Folder test1 = store.getDefaultFolder().getFolder("test1");
+            final Folder test2 = store.getDefaultFolder().getFolder("test2");
+
+            assertTrue(test1.renameTo(test2), "rename test1 -> test2 must succeed");
+            assertTrue(store.getDefaultFolder().getFolder("test2").renameTo(test1),
+                    "rename test2 -> test1 (rename back) must succeed");
+
+            // a later session opens the folder, as the next TCK test would
+            final Store store2 = connect();
+            try {
+                final Folder reopened = store2.getDefaultFolder().getFolder("test1");
+                reopened.open(Folder.READ_ONLY);
+                assertEquals(1, reopened.getMessageCount());
+                reopened.close(false);
+            } finally {
+                store2.close();
+            }
+        } finally {
+            store.close();
+        }
+    }
+}
diff --git a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/testserver/MailServer.java b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/testserver/MailServer.java
index 1a1d194..adfd6be 100644
--- a/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/testserver/MailServer.java
+++ b/geronimo-mail_2.1_impl/geronimo-mail_2.1_provider/src/test/java/org/apache/geronimo/mail/testserver/MailServer.java
@@ -313,6 +313,27 @@ public class MailServer {
 
     }
 
+    /**
+     * Creates (if necessary) a top-level mailbox with the given name for the test user
+     * (i.e. a sibling of INBOX, like the "test1" folder used by the Jakarta Mail TCK).
+     */
+    public void createUserMailbox(final String name) throws Exception {
+        final MailboxSession session = mailboxManager.createSystemSession(Username.of(USER));
+        final MailboxPath path = MailboxPath.forUser(Username.of(USER), name);
+        if (!Mono.from(mailboxManager.mailboxExists(path, session)).block()) {
+            mailboxManager.createMailbox(path, session);
+        }
+    }
+
+    /**
+     * Appends a raw rfc822 message to the given top-level mailbox of the test user.
+     */
+    public void appendToUserMailbox(final String name, final byte[] content) throws Exception {
+        final MailboxSession session = mailboxManager.createSystemSession(Username.of(USER));
+        final MessageManager mb = mailboxManager.getMailbox(MailboxPath.forUser(Username.of(USER), name), session);
+        mb.appendMessage(MessageManager.AppendCommand.builder().recent().build(content), session);
+    }
+
     /**
      * @return the queue
      */
diff --git a/geronimo-mail_2.1_tck/src/tck/geronimo.jtx b/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
index 2186494..b9c46cd 100644
--- a/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
+++ b/geronimo-mail_2.1_tck/src/tck/geronimo.jtx
@@ -37,11 +37,11 @@ javasoft/sqe/tests/jakarta/mail/UIDFolder/testlist.html#getUIDNext_Test
 # should be reviewed separately.
 SignatureTest.html
 
-# Remaining baseline failures from the first full run (191 passed / 125 failed).
-# Large blocks share single root causes:
-#  - Message/Multipart/Folder blocks: IMAPFolder.open (SELECT) rejected by
-#    James 3.9 (CommandFailedException), plus folder create/rename defects
-javasoft/sqe/tests/jakarta/mail/event/FolderEvent/testlist.html#addFolderListener_Test
+
+# Remaining baseline failures (284 passed / 31 failed after the
+# IMAPFolder.renameTo fix removed a ~90-test cascade). Distinct defects:
+# folder create/delete (topdog), permanent flags, list/listSubscribed,
+# several MIME encoding/decoding and unicode behaviours.
 javasoft/sqe/tests/jakarta/mail/event/FolderEvent/testlist.html#addMsgChangeList_Test
 javasoft/sqe/tests/jakarta/mail/exception/testlist.html#folderNotFoundExp_Test
 javasoft/sqe/tests/jakarta/mail/exception/testlist.html#msgRemoveExp_Test
@@ -55,113 +55,21 @@ javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#getPermanentFlags_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#getType_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#list_Test
 javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#listSubscribed_Test
-javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#renameTo_Test
-javasoft/sqe/tests/jakarta/mail/Folder/testlist.html#search_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetAddress/testlist.html#getType_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetAddress/testlist.html#internetAddress_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetAddress/testlist.html#setAddress_Test
 javasoft/sqe/tests/jakarta/mail/internet/InternetAddress/testlist.html#unicode_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getAllHeaderLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getAllHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getMatchingHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getNonMatchHead_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#getNonMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#InternetHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/InternetHeaders/testlist.html#load_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#attachFile_saveFile_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getAllHeaderLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getAllHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getContent_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getContentID_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getContentLanguage_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getContentMD5_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getContentType_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getDataHandler_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getDescription_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getDisposition_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getEncoding_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getFileName_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getHeader_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getLineCount_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getMatchingHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getNonMatchHead_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getNonMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#getSize_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#isMimeType_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#mimeBodyPart_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#setContentLanguage_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#setFileNameEncoded_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeBodyPart/testlist.html#writeTo_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#addRecipients_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getAllHeaderLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getContentID_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getContentLanguage_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getContentMD5_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getEncoding_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getHeader_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getInputStream_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getNonMatchHeadLines_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#getSentDate_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#MimeMessage_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#setDataHandler_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#setFileNameEncoded_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#setSentDate_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#unicode_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#updateHeaders_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMessage/testlist.html#writeTo_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMultipart/testlist.html#getBodyPart_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimeMultipart/testlist.html#getCount_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMultipart/testlist.html#getsetPreamble_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeMultipart/testlist.html#writeTo_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimePartDataSource/testlist.html#getContentType_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimePartDataSource/testlist.html#getInputStream_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimePartDataSource/testlist.html#getName_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimePartDataSource/testlist.html#getOutputStream_Test
-javasoft/sqe/tests/jakarta/mail/internet/MimePartDataSource/testlist.html#mimePartDataSource_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeUtility/testlist.html#decodeText_Test
 javasoft/sqe/tests/jakarta/mail/internet/MimeUtility/testlist.html#foldUnfold_Test
 javasoft/sqe/tests/jakarta/mail/internet/ParameterList/testlist.html#set_withDecodeStrict_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getAllHeaders_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getContent_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getContentType_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getDataHandler_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getDescription_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getDisposition_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getFileName_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getFlags_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getFolder_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getFrom_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getHeader_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getInputStream_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getMatchingHeaders_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getMessageNumber_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getNonMatchingHeaders_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getReceivedDate_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getReplyTo_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getSize_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#getSubject_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#isExpunged_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#isSet_Test
-javasoft/sqe/tests/jakarta/mail/Message/testlist.html#match_Test
 javasoft/sqe/tests/jakarta/mail/Message/testlist.html#setFileName_Test
 javasoft/sqe/tests/jakarta/mail/Message/testlist.html#setFileNameTest_encodeFalse_decodeTrue
-javasoft/sqe/tests/jakarta/mail/Multipart/testlist.html#getBodyPart_Test
-javasoft/sqe/tests/jakarta/mail/Multipart/testlist.html#getContentType_Test
-javasoft/sqe/tests/jakarta/mail/Multipart/testlist.html#getCount_Test
 javasoft/sqe/tests/jakarta/mail/Multipart/testlist.html#writeTo_Test
-javasoft/sqe/tests/jakarta/mail/search/AndTerm/testlist.html#andterm_Test
-javasoft/sqe/tests/jakarta/mail/search/BodyTerm/testlist.html#bodyterm_Test
-javasoft/sqe/tests/jakarta/mail/search/FlagTerm/testlist.html#flagterm_Test
-javasoft/sqe/tests/jakarta/mail/search/FromTerm/testlist.html#fromterm_Test
-javasoft/sqe/tests/jakarta/mail/search/HeaderTerm/testlist.html#headerterm_Test
-javasoft/sqe/tests/jakarta/mail/search/MessageIDTerm/testlist.html#messageidterm_Test
-javasoft/sqe/tests/jakarta/mail/search/MessageNumberTerm/testlist.html#messagenumberterm_Test
-javasoft/sqe/tests/jakarta/mail/search/NotTerm/testlist.html#notterm_Test
-javasoft/sqe/tests/jakarta/mail/search/OrTerm/testlist.html#orterm_Test
-javasoft/sqe/tests/jakarta/mail/search/ReceivedDateTerm/testlist.html#receiveddateterm_Test
-javasoft/sqe/tests/jakarta/mail/search/SentDateTerm/testlist.html#sentdateterm_Test
-javasoft/sqe/tests/jakarta/mail/search/SizeTerm/testlist.html#sizeterm_Test
-javasoft/sqe/tests/jakarta/mail/search/SubjectTerm/testlist.html#subjectterm_Test