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

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

commit f44aeed5630bc38316424c1e4d218fb360b4129b
Author: Benoit Tellier <[email protected]>
AuthorDate: Tue Apr 7 10:30:08 2020 +0700

    JAMES-3136 Switch imapUidDAO into source of truth for CassandraMessageMapper
    
    Write to it first, then denormalize to `messageIdTable`.
    
    Tests the various failures that can occur on the write path for
    CassandraMessageMapper.
---
 .../cassandra/mail/CassandraMessageMapper.java     |   6 +-
 .../cassandra/mail/CassandraMessageMapperTest.java | 133 +++++++++++++++++++++
 .../store/mail/model/MessageMapperTest.java        |  24 ++--
 3 files changed, 147 insertions(+), 16 deletions(-)

diff --git 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
index 23dbc07..807b891 100644
--- 
a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
+++ 
b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapper.java
@@ -405,10 +405,8 @@ public class CassandraMessageMapper implements 
MessageMapper {
                 .flags(message.createFlags())
                 .modSeq(message.getModSeq())
                 .build();
-        return Flux.merge(
-                messageIdDAO.insert(composedMessageIdWithMetaData),
-                imapUidDAO.insert(composedMessageIdWithMetaData))
-            .then();
+        return imapUidDAO.insert(composedMessageIdWithMetaData)
+            .then(messageIdDAO.insert(composedMessageIdWithMetaData));
     }
 
 
diff --git 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
index acfacf3..fb647c0 100644
--- 
a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
+++ 
b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageMapperTest.java
@@ -19,11 +19,25 @@
 
 package org.apache.james.mailbox.cassandra.mail;
 
+import static org.apache.james.backends.cassandra.Scenario.Builder.fail;
+
+import java.util.Optional;
+
+import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
+import org.apache.james.mailbox.cassandra.ids.CassandraId;
+import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
+import org.apache.james.mailbox.model.MessageRange;
+import org.apache.james.mailbox.store.mail.MessageMapper;
 import org.apache.james.mailbox.store.mail.model.MapperProvider;
 import org.apache.james.mailbox.store.mail.model.MessageMapperTest;
+import org.assertj.core.api.SoftAssertions;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
+import com.github.fge.lambdas.Throwing;
+
 class CassandraMessageMapperTest extends MessageMapperTest {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new 
CassandraClusterExtension(MailboxAggregateModule.MODULE);
@@ -32,4 +46,123 @@ class CassandraMessageMapperTest extends MessageMapperTest {
     protected MapperProvider createMapperProvider() {
         return new 
CassandraMapperProvider(cassandraCluster.getCassandraCluster());
     }
+
+    @Nested
+    class FailureTesting {
+        @Test
+        void 
retrieveMessagesShouldNotReturnMessagesWhenFailToPersistInMessageDAO(CassandraCluster
 cassandra) {
+            cassandra.getConf()
+                .registerScenario(fail()
+                    .forever()
+                    .whenQueryStartsWith("INSERT INTO messageV2 
(messageId,internalDate,bodyStartOctet,fullContentOctets,bodyOctets,bodyContent,headerContent,properties,textualLineCount,attachments)"));
+
+            try {
+                messageMapper.add(benwaInboxMailbox, message1);
+            } catch (Exception e) {
+                // ignoring expected error
+            }
+
+            CassandraMessageIdDAO messageIdDAO = new 
CassandraMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                
softly.assertThat(messageMapper.findInMailbox(benwaInboxMailbox, 
MessageRange.all(), MessageMapper.FetchType.Metadata, 1))
+                    .toIterable()
+                    .isEmpty();
+                softly.assertThat(messageIdDAO.retrieveMessages((CassandraId) 
benwaInboxMailbox.getMailboxId(), MessageRange.all()).collectList().block())
+                    .isEmpty();
+            }));
+        }
+
+        @Test
+        void 
retrieveMessagesShouldNotReturnMessagesWhenFailsToPersistBlobParts(CassandraCluster
 cassandra) {
+            cassandra.getConf()
+                .registerScenario(fail()
+                    .forever()
+                    .whenQueryStartsWith("INSERT INTO blobParts 
(id,chunkNumber,data) VALUES (:id,:chunkNumber,:data);"));
+
+            try {
+                messageMapper.add(benwaInboxMailbox, message1);
+            } catch (Exception e) {
+                // ignoring expected error
+            }
+
+            CassandraMessageIdDAO messageIdDAO = new 
CassandraMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                
softly.assertThat(messageMapper.findInMailbox(benwaInboxMailbox, 
MessageRange.all(), MessageMapper.FetchType.Metadata, 1))
+                    .toIterable()
+                    .isEmpty();
+                softly.assertThat(messageIdDAO.retrieveMessages((CassandraId) 
benwaInboxMailbox.getMailboxId(), MessageRange.all()).collectList().block())
+                    .isEmpty();
+            }));
+        }
+
+        @Test
+        void 
retrieveMessagesShouldNotReturnMessagesWhenFailsToPersistBlobs(CassandraCluster 
cassandra) {
+            cassandra.getConf()
+                .registerScenario(fail()
+                    .forever()
+                    .whenQueryStartsWith("INSERT INTO blobs (id,position) 
VALUES (:id,:position);"));
+
+            try {
+                messageMapper.add(benwaInboxMailbox, message1);
+            } catch (Exception e) {
+                // ignoring expected error
+            }
+
+            CassandraMessageIdDAO messageIdDAO = new 
CassandraMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                
softly.assertThat(messageMapper.findInMailbox(benwaInboxMailbox, 
MessageRange.all(), MessageMapper.FetchType.Metadata, 1))
+                    .toIterable()
+                    .isEmpty();
+                softly.assertThat(messageIdDAO.retrieveMessages((CassandraId) 
benwaInboxMailbox.getMailboxId(), MessageRange.all()).collectList().block())
+                    .isEmpty();
+            }));
+        }
+
+        @Test
+        void 
retrieveMessagesShouldNotReturnMessagesWhenFailsToPersistInImapUidTable(CassandraCluster
 cassandra) {
+            cassandra.getConf()
+                .registerScenario(fail()
+                    .forever()
+                    .whenQueryStartsWith("INSERT INTO imapUidTable 
(messageId,mailboxId,uid,modSeq,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+
+            try {
+                messageMapper.add(benwaInboxMailbox, message1);
+            } catch (Exception e) {
+                // ignoring expected error
+            }
+
+            CassandraMessageIdDAO messageIdDAO = new 
CassandraMessageIdDAO(cassandra.getConf(), new CassandraMessageId.Factory());
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                
softly.assertThat(messageMapper.findInMailbox(benwaInboxMailbox, 
MessageRange.all(), MessageMapper.FetchType.Metadata, 1))
+                    .toIterable()
+                    .isEmpty();
+                softly.assertThat(messageIdDAO.retrieveMessages((CassandraId) 
benwaInboxMailbox.getMailboxId(), MessageRange.all()).collectList().block())
+                    .isEmpty();
+            }));
+        }
+
+        @Test
+        void 
addShouldPersistInTableOfTruthWhenMessageIdTableWritesFails(CassandraCluster 
cassandra) {
+            cassandra.getConf()
+                .registerScenario(fail()
+                    .forever()
+                    .whenQueryStartsWith("INSERT INTO messageIdTable 
(mailboxId,uid,modSeq,messageId,flagAnswered,flagDeleted,flagDraft,flagFlagged,flagRecent,flagSeen,flagUser,userFlags)"));
+
+            try {
+                messageMapper.add(benwaInboxMailbox, message1);
+            } catch (Exception e) {
+                // ignoring expected error
+            }
+
+            CassandraMessageIdToImapUidDAO imapUidDAO = new 
CassandraMessageIdToImapUidDAO(cassandra.getConf(), new 
CassandraMessageId.Factory());
+
+            SoftAssertions.assertSoftly(Throwing.consumer(softly -> {
+                
softly.assertThat(messageMapper.findInMailbox(benwaInboxMailbox, 
MessageRange.all(), MessageMapper.FetchType.Metadata, 1))
+                    .toIterable()
+                    .isEmpty();
+                softly.assertThat(imapUidDAO.retrieve((CassandraMessageId) 
message1.getMessageId(), Optional.empty()).collectList().block())
+                    .hasSize(1);
+            }));
+        }
+    }
 }
diff --git 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
index 11cf811..ae67a36 100644
--- 
a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
+++ 
b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageMapperTest.java
@@ -77,18 +77,18 @@ public abstract class MessageMapperTest {
     private static final Username BENWA = Username.of("benwa");
 
     private MapperProvider mapperProvider;
-    private MessageMapper messageMapper;
+    protected MessageMapper messageMapper;
     private MailboxMapper mailboxMapper;
 
-    private Mailbox benwaInboxMailbox;
-    private Mailbox benwaWorkMailbox;
-    
-    private MailboxMessage message1;
-    private MailboxMessage message2;
-    private MailboxMessage message3;
-    private MailboxMessage message4;
-    private MailboxMessage message5;
-    private MailboxMessage message6;
+    protected Mailbox benwaInboxMailbox;
+    protected Mailbox benwaWorkMailbox;
+
+    protected MailboxMessage message1;
+    protected MailboxMessage message2;
+    protected MailboxMessage message3;
+    protected MailboxMessage message4;
+    protected MailboxMessage message5;
+    protected MailboxMessage message6;
 
     protected abstract MapperProvider createMapperProvider();
 
@@ -1203,8 +1203,8 @@ public abstract class MessageMapperTest {
     private Mailbox createMailbox(MailboxPath mailboxPath) throws 
MailboxException {
         return mailboxMapper.create(mailboxPath, UID_VALIDITY);
     }
-    
-    private void saveMessages() throws MailboxException {
+
+    protected void saveMessages() throws MailboxException {
         messageMapper.add(benwaInboxMailbox, message1);
         message1.setModSeq(messageMapper.getHighestModSeq(benwaInboxMailbox));
         messageMapper.add(benwaInboxMailbox, message2);


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

Reply via email to