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 d65b1a08178cbec530adfdeb3d6763e05518427a
Author: Benoit Tellier <[email protected]>
AuthorDate: Thu Feb 24 09:18:44 2022 +0700

    JAMES-3715 Adds tests for IMAP partial fetch over Netty transport
    
    Under some circumstances those broke with Netty4 and the little test
    suite introduced here reliably demonstrates this.
    
    Furthermore, we identified an issue regarding partial fetch when only
    the offset is specified. This is due to the usage of Long.MAX_VALUE to
    represent absence, and that causes some mis-calculations down the line.
---
 .../fetch/PartialFetchBodyElementTest.java         | 35 +++++++---
 .../james/imapserver/netty/IMAPServerTest.java     | 79 ++++++++++++++++++++++
 .../org/apache/james/utils/TestIMAPClient.java     |  2 +-
 3 files changed, 106 insertions(+), 10 deletions(-)

diff --git 
a/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/PartialFetchBodyElementTest.java
 
b/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/PartialFetchBodyElementTest.java
index 5a8f2d4..a35226d 100644
--- 
a/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/PartialFetchBodyElementTest.java
+++ 
b/protocols/imap/src/test/java/org/apache/james/imap/processor/fetch/PartialFetchBodyElementTest.java
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.when;
 
 import org.apache.james.imap.message.response.FetchResponse.BodyElement;
 import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
 import org.junit.jupiter.api.Test;
 
 class PartialFetchBodyElementTest {
@@ -39,8 +40,7 @@ class PartialFetchBodyElementTest {
     }
 
     @Test
-    void testSizeShouldBeNumberOfOctetsWhenSizeMoreWhenStartIsZero()
-            throws Exception {
+    void testSizeShouldBeNumberOfOctetsWhenSizeMoreWhenStartIsZero() throws 
Exception {
         final long moreThanNumberOfOctets = NUMBER_OF_OCTETS + 1;
         PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 0, NUMBER_OF_OCTETS);
         when(mockBodyElement.size()).thenReturn(moreThanNumberOfOctets);
@@ -49,8 +49,7 @@ class PartialFetchBodyElementTest {
     }
 
     @Test
-    void testSizeShouldBeSizeWhenNumberOfOctetsMoreWhenStartIsZero()
-            throws Exception {
+    void testSizeShouldBeSizeWhenNumberOfOctetsMoreWhenStartIsZero() throws 
Exception {
         final long lessThanNumberOfOctets = NUMBER_OF_OCTETS - 1;
         PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 0, NUMBER_OF_OCTETS);
         when(mockBodyElement.size()).thenReturn(lessThanNumberOfOctets);
@@ -59,8 +58,7 @@ class PartialFetchBodyElementTest {
     }
 
     @Test
-    void 
testWhenStartPlusNumberOfOctetsIsMoreThanSizeSizeShouldBeSizeMinusStart()
-            throws Exception {
+    void 
testWhenStartPlusNumberOfOctetsIsMoreThanSizeSizeShouldBeSizeMinusStart() 
throws Exception {
         final long size = 60;
         PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 10, NUMBER_OF_OCTETS);
         when(mockBodyElement.size()).thenReturn(size);
@@ -70,7 +68,7 @@ class PartialFetchBodyElementTest {
 
     @Test
     void 
testWhenStartPlusNumberOfOctetsIsLessThanSizeSizeShouldBeNumberOfOctetsMinusStart()
-            throws Exception {
+        throws Exception {
         final long size = 100;
         PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 10, NUMBER_OF_OCTETS);
         when(mockBodyElement.size()).thenReturn(size);
@@ -88,12 +86,31 @@ class PartialFetchBodyElementTest {
     }
 
     @Test
-    void testSizeShouldBeNumberOfOctetsWhenStartMoreThanOctets()
-            throws Exception {
+    void testSizeShouldBeNumberOfOctetsWhenStartMoreThanOctets() throws 
Exception {
         final long size = 2000;
         PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 1000, NUMBER_OF_OCTETS);
         when(mockBodyElement.size()).thenReturn(size);
 
         assertThat(element.size()).describedAs("Content size is less than 
start. Size should be zero.").isEqualTo(NUMBER_OF_OCTETS);
     }
+
+    @Test
+    void 
testSizeShouldBeNumberOfOctetsWhenSizeMoreWhenStartIsZeroAndNoLimitSpecified() 
throws Exception {
+        PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 0, Long.MAX_VALUE);
+        when(mockBodyElement.size()).thenReturn(NUMBER_OF_OCTETS);
+
+        assertThat(element.size()).describedAs("Size is more than number of 
octets so should be number of octets")
+            .isEqualTo(NUMBER_OF_OCTETS);
+    }
+
+    @Disabled("JAMES-3715 A bug due to usage of Long.MAX to represent a value 
that is absent prevents this" +
+        "from working decently. Returns 9223372036854775807L which cannot be 
parsed nor handled by IMAP clients.")
+    @Test
+    void 
testWhenStartPlusNumberOfOctetsIsMoreThanSizeSizeShouldBeSizeMinusStartAndNoLimitSpecified()
 throws Exception {
+        final long size = 60;
+        PartialFetchBodyElement element = new 
PartialFetchBodyElement(mockBodyElement, 10, Long.MAX_VALUE);
+        when(mockBodyElement.size()).thenReturn(size);
+
+        assertThat(element.size()).describedAs("Size is less than number of 
octets so should be size").isEqualTo(50);
+    }
 }
diff --git 
a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
 
b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
index 6222c4d..4094f8d 100644
--- 
a/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
+++ 
b/server/protocols/protocols-imap4/src/test/java/org/apache/james/imapserver/netty/IMAPServerTest.java
@@ -141,6 +141,85 @@ class IMAPServerTest {
     }
 
     @Nested
+    class PartialFetch {
+        IMAPServer imapServer;
+        private int port;
+
+        @BeforeEach
+        void beforeEach() throws Exception {
+            imapServer = createImapServer("imapServer.xml");
+            port = imapServer.getListenAddresses().get(0).getPort();
+        }
+
+        @AfterEach
+        void tearDown() {
+            imapServer.destroy();
+        }
+
+        @Test
+        void fetchShouldRetrieveMessage() throws Exception {
+            testIMAPClient.connect("127.0.0.1", port)
+                .login(USER.asString(), USER_PASS)
+                .append("INBOX", SMALL_MESSAGE);
+
+            assertThat(testIMAPClient
+                    .select("INBOX")
+                    .readFirstMessage())
+                .contains("* 1 FETCH (FLAGS (\\Recent \\Seen) BODY[] 
{21}\r\nheader: value\r\n\r\nBODY)\r\n");
+        }
+
+        @Test
+        void 
fetchShouldRetrieveMessageWhenOffsetAndLimitExceedingMessageSize() throws 
Exception {
+            testIMAPClient.connect("127.0.0.1", port)
+                .login(USER.asString(), USER_PASS)
+                .append("INBOX", SMALL_MESSAGE);
+
+            assertThat(testIMAPClient
+                    .select("INBOX")
+                    .readFirstMessageInMailbox("BODY[]<8.20>"))
+                .contains("* 1 FETCH (FLAGS (\\Recent \\Seen) BODY[]<8> 
{13}\r\nvalue\r\n\r\nBODY)\r\n");
+        }
+
+        @Test
+        void fetchShouldRetrieveMessageWhenOffsetAndLimitEqualMessageSize() 
throws Exception {
+            testIMAPClient.connect("127.0.0.1", port)
+                .login(USER.asString(), USER_PASS)
+                .append("INBOX", SMALL_MESSAGE);
+
+            assertThat(testIMAPClient
+                    .select("INBOX")
+                    .readFirstMessageInMailbox("BODY[]<8.13>"))
+                .contains("* 1 FETCH (FLAGS (\\Recent \\Seen) BODY[]<8> 
{13}\r\nvalue\r\n\r\nBODY)\r\n");
+        }
+
+        @Test
+        void fetchShouldRetrieveMessageWhenOffsetAndLimitBelowMessageSize() 
throws Exception {
+            testIMAPClient.connect("127.0.0.1", port)
+                .login(USER.asString(), USER_PASS)
+                .append("INBOX", SMALL_MESSAGE);
+
+            assertThat(testIMAPClient
+                    .select("INBOX")
+                    .readFirstMessageInMailbox("BODY[]<8.12>"))
+                .contains("* 1 FETCH (FLAGS (\\Recent \\Seen) BODY[]<8> 
{12}\r\nvalue\r\n\r\nBOD)\r\n");
+        }
+
+        @Disabled("JAMES-3715 A bug due to usage of Long.MAX to represent a 
value that is absent prevents this" +
+            "from working decently.")
+        @Test
+        void fetchShouldRetrieveMessageWhenOffsetAndNoLimitSpecified() throws 
Exception {
+            testIMAPClient.connect("127.0.0.1", port)
+                .login(USER.asString(), USER_PASS)
+                .append("INBOX", SMALL_MESSAGE);
+
+            assertThat(testIMAPClient
+                    .select("INBOX")
+                    .readFirstMessageInMailbox("BODY[]<8>"))
+                .contains("* 1 FETCH (FLAGS (\\Recent \\Seen) BODY[]<8> 
{13}\r\nvalue\r\n\r\nBODY)\r\n");
+        }
+    }
+
+    @Nested
     class NoLimit {
         IMAPServer imapServer;
         private int port;
diff --git 
a/server/testing/src/main/java/org/apache/james/utils/TestIMAPClient.java 
b/server/testing/src/main/java/org/apache/james/utils/TestIMAPClient.java
index 72f1c79..25041a5 100644
--- a/server/testing/src/main/java/org/apache/james/utils/TestIMAPClient.java
+++ b/server/testing/src/main/java/org/apache/james/utils/TestIMAPClient.java
@@ -220,7 +220,7 @@ public class TestIMAPClient extends ExternalResource 
implements Closeable, After
         return imapClient.getReplyString();
     }
 
-    private String readFirstMessageInMailbox(String parameters) throws 
IOException {
+    public String readFirstMessageInMailbox(String parameters) throws 
IOException {
         imapClient.fetch("1:1", parameters);
         return imapClient.getReplyString();
     }

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

Reply via email to