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 rc...@apache.org on 2020/04/10 02:02:10 UTC
[james-project] 02/15: JAMES-3136 Switch imapUidDAO into source of
truth for CassandraMessageMapper
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 <bt...@linagora.com>
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: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org