blob: 6e35beb6d496bd8e8f4a2275d8bbf498e35fd96e [file] [log] [blame]
/****************************************************************
* 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.james.mailbox.cassandra;
import static org.apache.james.backends.cassandra.Scenario.Builder.fail;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import java.util.Collection;
import java.util.Optional;
import javax.mail.Flags;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.james.backends.cassandra.CassandraCluster;
import org.apache.james.backends.cassandra.CassandraClusterExtension;
import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
import org.apache.james.backends.cassandra.utils.CassandraUtils;
import org.apache.james.blob.api.BlobStore;
import org.apache.james.blob.api.HashBlobId;
import org.apache.james.core.Username;
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.cassandra.ids.CassandraId;
import org.apache.james.mailbox.cassandra.ids.CassandraMessageId;
import org.apache.james.mailbox.cassandra.mail.CassandraACLMapper;
import org.apache.james.mailbox.cassandra.mail.CassandraApplicableFlagDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentDAOV2;
import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentMessageIdDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraAttachmentOwnerDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraDeletedMessageDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraFirstUnseenDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraMailboxCounterDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraMailboxRecentsDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraMessageDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraMessageIdToImapUidDAO;
import org.apache.james.mailbox.cassandra.mail.CassandraUserMailboxRightsDAO;
import org.apache.james.mailbox.cassandra.mail.MailboxAggregateModule;
import org.apache.james.mailbox.events.EventBus;
import org.apache.james.mailbox.model.AttachmentId;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxPath;
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.mail.MessageMapper;
import org.apache.james.metrics.tests.RecordingMetricFactory;
import org.apache.james.util.ClassLoaderUtils;
import org.apache.james.util.streams.Iterators;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.testcontainers.shaded.com.google.common.collect.ImmutableList;
import com.github.fge.lambdas.Throwing;
public class CassandraMailboxManagerTest extends MailboxManagerTest<CassandraMailboxManager> {
public static final Username BOB = Username.of("Bob");
@RegisterExtension
static CassandraClusterExtension cassandra = new CassandraClusterExtension(MailboxAggregateModule.MODULE_WITH_QUOTA);
@Override
protected CassandraMailboxManager provideMailboxManager() {
return CassandraMailboxManagerProvider.provideMailboxManager(
cassandra.getCassandraCluster(),
new PreDeletionHooks(preDeletionHooks(), new RecordingMetricFactory()));
}
@Override
protected EventBus retrieveEventBus(CassandraMailboxManager mailboxManager) {
return mailboxManager.getEventBus();
}
@Nested
class DeletionTests {
private MailboxSession session;
private MailboxPath inbox;
private MailboxId inboxId;
private MessageManager inboxManager;
private MessageManager otherBoxManager;
private MailboxPath newPath;
@BeforeEach
void setUp() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
inbox = MailboxPath.inbox(session);
newPath = MailboxPath.forUser(USER_1, "specialMailbox");
inboxId = mailboxManager.createMailbox(inbox, session).get();
inboxManager = mailboxManager.getMailbox(inbox, session);
MailboxId otherId = mailboxManager.createMailbox(newPath, session).get();
otherBoxManager = mailboxManager.getMailbox(otherId, session);
}
@Test
void deleteMailboxShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM attachmentV2 WHERE idAsUUID=:idAsUUID;"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM messageV2 WHERE messageId=:messageId;"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM messageIdTable"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldEventuallyUnreferenceMessageMetadataWhenDeleteMailboxContextByIdFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM imapUidTable"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteShouldUnreferenceMessageMetadata(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteShouldUnreferenceMessageMetadataWhenDeleteMessageFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM messageV2 WHERE messageId=:messageId;"));
inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteShouldUnreferenceMessageMetadataWhenDeleteAttachmentFails(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM attachmentV2 WHERE idAsUUID=:idAsUUID;"));
inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isEmpty();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
mailboxManager.copyMessages(MessageRange.all(), inboxId, otherBoxManager.getId(), session);
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isPresent();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isPresent();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.contains(cassandraMessageId);
});
}
@Test
void deleteShouldNotUnreferenceMessageMetadataWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
mailboxManager.copyMessages(MessageRange.all(), inboxId, otherBoxManager.getId(), session);
inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isPresent();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isPresent();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.contains(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
new CassandraAttachmentOwnerDAO(cassandraCluster.getConf()).addOwner(attachmentId, Username.of("bob")).block();
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
CassandraId mailboxId = (CassandraId) appendResult.getId().getMailboxId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(imapUidDAO(cassandraCluster).retrieve(cassandraMessageId, Optional.of(mailboxId)).collectList().block())
.isEmpty();
softly.assertThat(messageIdDAO(cassandraCluster).retrieveMessages(mailboxId, MessageRange.all()).collectList().block())
.isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isPresent();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteShouldNotUnreferenceAttachmentWhenOtherReference(CassandraCluster cassandraCluster) throws Exception {
AppendResult appendResult = inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
AttachmentId attachmentId = Iterators.toStream(inboxManager.getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session))
.map(Throwing.function(MessageResult::getLoadedAttachments))
.flatMap(Collection::stream)
.map(MessageAttachmentMetadata::getAttachmentId)
.findFirst()
.get();
new CassandraAttachmentOwnerDAO(cassandraCluster.getConf()).addOwner(attachmentId, Username.of("bob")).block();
inboxManager.delete(ImmutableList.of(appendResult.getId().getUid()), session);
SoftAssertions.assertSoftly(softly -> {
CassandraMessageId cassandraMessageId = (CassandraMessageId) appendResult.getId().getMessageId();
softly.assertThat(messageDAO(cassandraCluster).retrieveMessage(cassandraMessageId, MessageMapper.FetchType.Metadata)
.blockOptional()).isEmpty();
softly.assertThat(attachmentDAO(cassandraCluster).getAttachment(attachmentId).blockOptional())
.isPresent();
softly.assertThat(attachmentMessageIdDAO(cassandraCluster).getOwnerMessageIds(attachmentId).collectList().block())
.doesNotContain(cassandraMessageId);
});
}
@Test
void deleteMailboxShouldCleanupACL(CassandraCluster cassandraCluster) throws Exception {
mailboxManager.setRights(inboxId, new MailboxACL(
Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraId id = (CassandraId) this.inboxId;
softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
});
}
@Test
void deleteMailboxShouldCleanupACLWhenRightsDeleteFails(CassandraCluster cassandraCluster) throws Exception {
mailboxManager.setRights(inboxId, new MailboxACL(
Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM UserMailboxACL WHERE userName=:userName AND mailboxid=:mailboxid;"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraId id = (CassandraId) this.inboxId;
softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
});
}
@Test
void deleteMailboxShouldCleanupACLWhenACLDeleteFails(CassandraCluster cassandraCluster) throws Exception {
mailboxManager.setRights(inboxId, new MailboxACL(
Pair.of(MailboxACL.EntryKey.createUserEntryKey(BOB), new MailboxACL.Rfc4314Rights(MailboxACL.Right.Read))), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM acl WHERE id=:id IF EXISTS;"));
mailboxManager.deleteMailbox(inbox, session);
SoftAssertions.assertSoftly(softly -> {
CassandraId id = (CassandraId) this.inboxId;
softly.assertThat(aclMapper(cassandraCluster).getACL(id).blockOptional()).isEmpty();
softly.assertThat(rightsDAO(cassandraCluster).listRightsForUser(BOB).collectList().block()).isEmpty();
});
}
@Test
void deleteMailboxShouldCleanUpApplicableFlags(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags("custom"))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(applicableFlagDAO(cassandraCluster).retrieveApplicableFlag((CassandraId) inboxId).blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpApplicableFlagsAfterAFailure(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags("custom"))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM applicableFlag WHERE mailboxId=:mailboxId;"));
mailboxManager.deleteMailbox(inbox, session);
assertThat(applicableFlagDAO(cassandraCluster).retrieveApplicableFlag((CassandraId) inboxId).blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpFirstUnseenWhenFail(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags())
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(firstUnseenDAO(cassandraCluster).retrieveFirstUnread((CassandraId) inboxId).blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpFirstUnseen(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags())
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM firstUnseen WHERE mailboxId=:mailboxId;"));
mailboxManager.deleteMailbox(inbox, session);
assertThat(firstUnseenDAO(cassandraCluster).retrieveFirstUnread((CassandraId) inboxId).blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpDeletedMessages(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
.collectList()
.block())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpDeletedMessagesWhenFailure(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM messageDeleted WHERE mailboxId=:mailboxId;"));
mailboxManager.deleteMailbox(inbox, session);
assertThat(deletedMessageDAO(cassandraCluster).retrieveDeletedMessage((CassandraId) inboxId, MessageRange.all())
.collectList()
.block())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpMailboxCounters(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
.blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpMailboxCountersWhenFailure(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM mailboxCounters WHERE mailboxId=:mailboxId;"));
mailboxManager.deleteMailbox(inbox, session);
assertThat(countersDAO(cassandraCluster).retrieveMailboxCounters((CassandraId) inboxId)
.blockOptional())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpRecent(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.RECENT))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
.collectList()
.block())
.isEmpty();
}
@Test
void deleteMailboxShouldCleanUpRecentWhenFailure(CassandraCluster cassandraCluster) throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.RECENT))
.build(ClassLoaderUtils.getSystemResourceAsByteArray("eml/emailWithOnlyAttachment.eml")), session);
cassandraCluster.getConf().registerScenario(fail()
.times(1)
.whenQueryStartsWith("DELETE FROM mailboxRecents WHERE mailboxId=:mailboxId;"));
mailboxManager.deleteMailbox(inbox, session);
assertThat(new CassandraMailboxRecentsDAO(cassandraCluster.getConf()).getRecentMessageUidsInMailbox((CassandraId) inboxId)
.collectList()
.block())
.isEmpty();
}
private CassandraMailboxCounterDAO countersDAO(CassandraCluster cassandraCluster) {
return new CassandraMailboxCounterDAO(cassandraCluster.getConf());
}
private CassandraDeletedMessageDAO deletedMessageDAO(CassandraCluster cassandraCluster) {
return new CassandraDeletedMessageDAO(cassandraCluster.getConf());
}
private CassandraFirstUnseenDAO firstUnseenDAO(CassandraCluster cassandraCluster) {
return new CassandraFirstUnseenDAO(cassandraCluster.getConf());
}
private CassandraApplicableFlagDAO applicableFlagDAO(CassandraCluster cassandraCluster) {
return new CassandraApplicableFlagDAO(cassandraCluster.getConf());
}
private CassandraACLMapper aclMapper(CassandraCluster cassandraCluster) {
return new CassandraACLMapper(cassandraCluster.getConf(), rightsDAO(cassandraCluster), CassandraConfiguration.DEFAULT_CONFIGURATION);
}
private CassandraUserMailboxRightsDAO rightsDAO(CassandraCluster cassandraCluster) {
return new CassandraUserMailboxRightsDAO(cassandraCluster.getConf(), CassandraUtils.WITH_DEFAULT_CONFIGURATION);
}
private CassandraAttachmentMessageIdDAO attachmentMessageIdDAO(CassandraCluster cassandraCluster) {
return new CassandraAttachmentMessageIdDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
}
private CassandraAttachmentDAOV2 attachmentDAO(CassandraCluster cassandraCluster) {
return new CassandraAttachmentDAOV2(new HashBlobId.Factory(), cassandraCluster.getConf());
}
private CassandraMessageIdDAO messageIdDAO(CassandraCluster cassandraCluster) {
return new CassandraMessageIdDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
}
private CassandraMessageIdToImapUidDAO imapUidDAO(CassandraCluster cassandraCluster) {
return new CassandraMessageIdToImapUidDAO(cassandraCluster.getConf(), new CassandraMessageId.Factory());
}
private CassandraMessageDAO messageDAO(CassandraCluster cassandraCluster) {
return new CassandraMessageDAO(cassandraCluster.getConf(), cassandraCluster.getTypesProvider(),
mock(BlobStore.class), new HashBlobId.Factory(), new CassandraMessageId.Factory());
}
}
}