MAILBOX-337 mailbox should allow mass message deletion by messageId
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/5bfbc370 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/5bfbc370 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/5bfbc370 Branch: refs/heads/master Commit: 5bfbc37045ea2a73ce3d4b09ca3a5a55918cb9ee Parents: 75f1d70 Author: benwa <[email protected]> Authored: Thu May 24 16:11:57 2018 +0700 Committer: Matthieu Baechler <[email protected]> Committed: Fri May 25 11:07:39 2018 +0200 ---------------------------------------------------------------------- .../apache/james/mailbox/MessageIdManager.java | 12 +- .../james/mailbox/model/DeleteResult.java | 112 +++++++++++++++++++ .../mail/CassandraMessageIdMapper.java | 19 +++- .../mailbox/store/StoreMessageIdManager.java | 51 ++++++++- .../mailbox/store/mail/MessageIdMapper.java | 7 ++ .../AbstractMessageIdManagerSideEffectTest.java | 33 +++++- .../AbstractMessageIdManagerStorageTest.java | 34 +++++- .../store/mail/model/MessageIdMapperTest.java | 76 +++++++++++++ 8 files changed, 332 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/api/src/main/java/org/apache/james/mailbox/MessageIdManager.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageIdManager.java b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageIdManager.java index 4eaa41b..c61581d 100644 --- a/mailbox/api/src/main/java/org/apache/james/mailbox/MessageIdManager.java +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/MessageIdManager.java @@ -27,11 +27,14 @@ import javax.mail.Flags; import org.apache.james.mailbox.MessageManager.FlagsUpdateMode; import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.DeleteResult; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MessageId; import org.apache.james.mailbox.model.MessageResult; import org.apache.james.mailbox.model.MessageResult.FetchGroup; +import com.google.common.collect.ImmutableList; + public interface MessageIdManager { Set<MessageId> accessibleMessages(Collection<MessageId> messageIds, final MailboxSession mailboxSession) throws MailboxException; @@ -40,7 +43,14 @@ public interface MessageIdManager { List<MessageResult> getMessages(List<MessageId> messageId, FetchGroup minimal, MailboxSession mailboxSession) throws MailboxException; - void delete(MessageId messageId, List<MailboxId> mailboxIds, MailboxSession mailboxSession) throws MailboxException; + DeleteResult delete(MessageId messageId, List<MailboxId> mailboxIds, MailboxSession mailboxSession) throws MailboxException; + + DeleteResult delete(List<MessageId> messageId, MailboxSession mailboxSession) throws MailboxException; void setInMailboxes(MessageId messageId, Collection<MailboxId> mailboxIds, MailboxSession mailboxSession) throws MailboxException; + + default DeleteResult delete(MessageId messageId, MailboxSession mailboxSession) throws MailboxException { + return delete(ImmutableList.of(messageId), mailboxSession); + } + } http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/api/src/main/java/org/apache/james/mailbox/model/DeleteResult.java ---------------------------------------------------------------------- diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/DeleteResult.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/DeleteResult.java new file mode 100644 index 0000000..7bb4351 --- /dev/null +++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/DeleteResult.java @@ -0,0 +1,112 @@ +/**************************************************************** + * 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.model; + +import java.util.Collection; +import java.util.Objects; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; + +public class DeleteResult { + public static class Builder { + private final ImmutableSet.Builder<MessageId> destroyed; + private final ImmutableSet.Builder<MessageId> notFound; + + public Builder() { + destroyed = ImmutableSet.builder(); + notFound = ImmutableSet.builder(); + } + + public Builder addDestroyed(Collection<MessageId> messageIds) { + destroyed.addAll(messageIds); + return this; + } + + public Builder addNotFound(Collection<MessageId> messageIds) { + notFound.addAll(messageIds); + return this; + } + + public Builder addDestroyed(MessageId messageId) { + destroyed.add(messageId); + return this; + } + + public Builder addNotFound(MessageId messageId) { + notFound.add(messageId); + return this; + } + + public DeleteResult build() { + return new DeleteResult( + destroyed.build(), + notFound.build()); + } + } + + public static Builder builder() { + return new Builder(); + } + + public static DeleteResult destroyed(MessageId messageId) { + return new Builder() + .addDestroyed(messageId) + .build(); + } + + public static DeleteResult notFound(MessageId messageId) { + return new Builder() + .addNotFound(messageId) + .build(); + } + + private final Set<MessageId> destroyed; + private final Set<MessageId> notFound; + + public DeleteResult(Set<MessageId> destroyed, Set<MessageId> notFound) { + this.destroyed = destroyed; + this.notFound = notFound; + } + + public Set<MessageId> getDestroyed() { + return destroyed; + } + + public Set<MessageId> getNotFound() { + return notFound; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof DeleteResult) { + DeleteResult result = (DeleteResult) o; + + return Objects.equals(this.destroyed, result.destroyed) + && Objects.equals(this.notFound, result.notFound); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(destroyed, notFound); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java index 4db9185..52ab41f 100644 --- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java +++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/CassandraMessageIdMapper.java @@ -57,6 +57,7 @@ import org.slf4j.LoggerFactory; import com.github.steveash.guavate.Guavate; import com.google.common.base.Throwables; +import com.google.common.collect.Multimap; public class CassandraMessageIdMapper implements MessageIdMapper { private static final Logger LOGGER = LoggerFactory.getLogger(CassandraMessageIdMapper.class); @@ -180,14 +181,26 @@ public class CassandraMessageIdMapper implements MessageIdMapper { @Override public void delete(MessageId messageId, Collection<MailboxId> mailboxIds) { + deleteAsFuture(messageId, mailboxIds).join(); + } + + public CompletableFuture<Void> deleteAsFuture(MessageId messageId, Collection<MailboxId> mailboxIds) { CassandraMessageId cassandraMessageId = (CassandraMessageId) messageId; - mailboxIds.stream() + return mailboxIds.stream() .map(mailboxId -> retrieveAndDeleteIndices(cassandraMessageId, Optional.of((CassandraId) mailboxId))) .reduce((f1, f2) -> CompletableFuture.allOf(f1, f2)) - .orElse(CompletableFuture.completedFuture(null)) - .join(); + .orElse(CompletableFuture.completedFuture(null)); } + @Override + public void delete(Multimap<MessageId, MailboxId> ids) { + FluentFutureStream.of( + ids.asMap() + .entrySet() + .stream() + .map(entry -> deleteAsFuture(entry.getKey(), entry.getValue()))) + .join(); + } private CompletableFuture<Void> retrieveAndDeleteIndices(CassandraMessageId messageId, Optional<CassandraId> mailboxId) { return imapUidDAO.retrieve(messageId, mailboxId) http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java index bcda820..1a5f789 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/StoreMessageIdManager.java @@ -39,6 +39,7 @@ import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.MessageUid; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.exception.MailboxNotFoundException; +import org.apache.james.mailbox.model.DeleteResult; import org.apache.james.mailbox.model.MailboxACL.Right; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.mailbox.model.MessageAttachment; @@ -58,6 +59,7 @@ import org.apache.james.mailbox.store.mail.model.FlagsFactory; import org.apache.james.mailbox.store.mail.model.FlagsFilter; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.apache.james.mailbox.store.mail.model.Message; import org.apache.james.mailbox.store.mail.model.impl.PropertyBuilder; import org.apache.james.mailbox.store.mail.model.impl.SimpleMailboxMessage; import org.apache.james.mailbox.store.quota.QuotaChecker; @@ -70,6 +72,7 @@ import com.github.steveash.guavate.Guavate; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Sets; public class StoreMessageIdManager implements MessageIdManager { @@ -162,23 +165,61 @@ public class StoreMessageIdManager implements MessageIdManager { } @Override - public void delete(MessageId messageId, List<MailboxId> mailboxIds, MailboxSession mailboxSession) throws MailboxException { + public DeleteResult delete(MessageId messageId, List<MailboxId> mailboxIds, MailboxSession mailboxSession) throws MailboxException { MessageIdMapper messageIdMapper = mailboxSessionMapperFactory.getMessageIdMapper(mailboxSession); - MailboxMapper mailboxMapper = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession); assertRightsOnMailboxes(mailboxIds, mailboxSession, Right.DeleteMessages); - ImmutableList<MetadataWithMailboxId> metadataWithMailbox = messageIdMapper + List<MailboxMessage> messageList = messageIdMapper .find(ImmutableList.of(messageId), MessageMapper.FetchType.Metadata) .stream() .filter(inMailboxes(mailboxIds)) + .collect(Guavate.toImmutableList()); + + if (!messageList.isEmpty()) { + delete(messageIdMapper, messageList, mailboxSession); + return DeleteResult.destroyed(messageId); + } + return DeleteResult.notFound(messageId); + } + + @Override + public DeleteResult delete(List<MessageId> messageIds, MailboxSession mailboxSession) throws MailboxException { + MessageIdMapper messageIdMapper = mailboxSessionMapperFactory.getMessageIdMapper(mailboxSession); + + List<MailboxMessage> messageList = messageIdMapper.find(messageIds, MessageMapper.FetchType.Metadata); + ImmutableSet<MailboxId> allowedMailboxIds = getAllowedMailboxIds(mailboxSession, messageList, Right.DeleteMessages); + + ImmutableSet<MessageId> accessibleMessages = messageList.stream() + .filter(message -> allowedMailboxIds.contains(message.getMailboxId())) + .map(MailboxMessage::getMessageId) + .distinct() + .collect(Guavate.toImmutableSet()); + Sets.SetView<MessageId> nonAccessibleMessages = Sets.difference(ImmutableSet.copyOf(messageIds), accessibleMessages); + + delete(messageIdMapper, messageList, mailboxSession); + + return DeleteResult.builder() + .addDestroyed(accessibleMessages) + .addNotFound(nonAccessibleMessages) + .build(); + } + + private void delete(MessageIdMapper messageIdMapper, List<MailboxMessage> messageList, MailboxSession mailboxSession) throws MailboxException { + ImmutableList<MetadataWithMailboxId> metadataWithMailbox = messageList.stream() .map(StoreMessageIdManager::toMetadataWithMailboxId) .collect(Guavate.toImmutableList()); - messageIdMapper.delete(messageId, mailboxIds); + messageIdMapper.delete( + messageList.stream() + .collect(Guavate.toImmutableListMultimap( + Message::getMessageId, + MailboxMessage::getMailboxId))); + MailboxMapper mailboxMapper = mailboxSessionMapperFactory.getMailboxMapper(mailboxSession); for (MetadataWithMailboxId metadataWithMailboxId : metadataWithMailbox) { - dispatcher.expunged(mailboxSession, metadataWithMailboxId.messageMetaData, mailboxMapper.findMailboxById(metadataWithMailboxId.mailboxId)); + dispatcher.expunged(mailboxSession, metadataWithMailboxId.messageMetaData, + mailboxMapper.findMailboxById(metadataWithMailboxId.mailboxId)); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageIdMapper.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageIdMapper.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageIdMapper.java index 9d5d4d9..2f9457f 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageIdMapper.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/mail/MessageIdMapper.java @@ -33,6 +33,8 @@ import org.apache.james.mailbox.model.UpdatedFlags; import org.apache.james.mailbox.store.mail.MessageMapper.FetchType; import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import com.google.common.collect.Multimap; + public interface MessageIdMapper { List<MailboxMessage> find(Collection<MessageId> messageIds, FetchType fetchType); @@ -47,5 +49,10 @@ public interface MessageIdMapper { void delete(MessageId messageId, Collection<MailboxId> mailboxIds); + default void delete(Multimap<MessageId, MailboxId> ids) { + ids.asMap() + .forEach(this::delete); + } + Map<MailboxId, UpdatedFlags> setFlags(MessageId messageId, List<MailboxId> mailboxIds, Flags newState, MessageManager.FlagsUpdateMode updateMode) throws MailboxException; } http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java index 3f38a6f..9f81ac0 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerSideEffectTest.java @@ -68,6 +68,7 @@ public abstract class AbstractMessageIdManagerSideEffectTest { .computedLimit(QuotaCount.count(100)) .build(); private static final MessageUid messageUid1 = MessageUid.of(111); + private static final MessageUid messageUid2 = MessageUid.of(113); public static final Flags FLAGS = new Flags(); @@ -98,7 +99,6 @@ public abstract class AbstractMessageIdManagerSideEffectTest { mailbox3 = testingData.createMailbox(MailboxFixture.SENT_ALICE, session); } - @Test public void deleteShouldCallEventDispatcher() throws Exception { givenUnlimitedQuota(); @@ -115,6 +115,25 @@ public abstract class AbstractMessageIdManagerSideEffectTest { } @Test + public void deletesShouldCallEventDispatcher() throws Exception { + givenUnlimitedQuota(); + MessageId messageId1 = testingData.persist(mailbox1.getMailboxId(), messageUid1, FLAGS, session); + MessageId messageId2 = testingData.persist(mailbox1.getMailboxId(), messageUid2, FLAGS, session); + reset(dispatcher); + + MessageResult messageResult1 = messageIdManager.getMessages(ImmutableList.of(messageId1), FetchGroupImpl.MINIMAL, session).get(0); + SimpleMessageMetaData simpleMessageMetaData1 = fromMessageResult(messageId1, messageResult1); + MessageResult messageResult2 = messageIdManager.getMessages(ImmutableList.of(messageId2), FetchGroupImpl.MINIMAL, session).get(0); + SimpleMessageMetaData simpleMessageMetaData2 = fromMessageResult(messageId2, messageResult2); + + messageIdManager.delete(ImmutableList.of(messageId1, messageId2), session); + + verify(dispatcher).expunged(session, simpleMessageMetaData1, mailbox1); + verify(dispatcher).expunged(session, simpleMessageMetaData2, mailbox1); + verifyNoMoreInteractions(dispatcher); + } + + @Test public void deleteShouldNotCallEventDispatcherWhenMessageIsInWrongMailbox() throws Exception { givenUnlimitedQuota(); MessageId messageId = testingData.persist(mailbox2.getMailboxId(), messageUid1, FLAGS, session); @@ -298,6 +317,18 @@ public abstract class AbstractMessageIdManagerSideEffectTest { } @Test + public void deletesShouldNotDispatchEventWhenMessageDoesNotExist() throws Exception { + givenUnlimitedQuota(); + MessageId messageId = testingData.createNotUsedMessageId(); + + reset(dispatcher); + + messageIdManager.delete(ImmutableList.of(messageId), session); + + verifyNoMoreInteractions(dispatcher); + } + + @Test public void setFlagsShouldNotDispatchEventWhenMessageDoesNotExist() throws Exception { givenUnlimitedQuota(); MessageId messageId = testingData.createNotUsedMessageId(); http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerStorageTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerStorageTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerStorageTest.java index 1e64270..e60c0ff 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerStorageTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/AbstractMessageIdManagerStorageTest.java @@ -33,9 +33,11 @@ import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MessageIdManager; import org.apache.james.mailbox.MessageManager; import org.apache.james.mailbox.MessageUid; +import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.exception.MailboxNotFoundException; import org.apache.james.mailbox.fixture.MailboxFixture; import org.apache.james.mailbox.mock.MockMailboxSession; +import org.apache.james.mailbox.model.DeleteResult; import org.apache.james.mailbox.model.FetchGroupImpl; import org.apache.james.mailbox.model.MailboxACL; import org.apache.james.mailbox.model.MailboxACL.Rfc4314Rights; @@ -101,10 +103,11 @@ public abstract class AbstractMessageIdManagerStorageTest { } @Test - public void deleteMessageShouldNotFailWhenMessageDoesNotExist() throws Exception { + public void deleteMessageShouldReturnNotFoundWhenMessageDoesNotExist() throws MailboxException { MessageId messageId = testingData.createNotUsedMessageId(); - messageIdManager.delete(messageId, ImmutableList.of(aliceMailbox1.getMailboxId()), aliceSession); + assertThat(messageIdManager.delete(messageId, bobSession)) + .isEqualTo(DeleteResult.notFound(messageId)); } @Test @@ -279,6 +282,15 @@ public abstract class AbstractMessageIdManagerStorageTest { } @Test + public void deleteAllMessageShouldRemoveMessageFromMailbox() throws Exception { + MessageId messageId = testingData.persist(aliceMailbox1.getMailboxId(), messageUid1, FLAGS, aliceSession); + + messageIdManager.delete(messageId, aliceSession); + + assertThat(messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, aliceSession)).isEmpty(); + } + + @Test public void deleteMessageShouldRemoveMessageOnlyFromMailbox() throws Exception { MessageId messageId = testingData.persist(aliceMailbox1.getMailboxId(), messageUid1, FLAGS, aliceSession); messageIdManager.setInMailboxes(messageId, ImmutableList.of(aliceMailbox1.getMailboxId(), aliceMailbox2.getMailboxId()), aliceSession); @@ -291,6 +303,16 @@ public abstract class AbstractMessageIdManagerStorageTest { } @Test + public void deleteAllShouldRemoveMessageFromAllMailbox() throws Exception { + MessageId messageId = testingData.persist(aliceMailbox1.getMailboxId(), messageUid1, FLAGS, aliceSession); + messageIdManager.setInMailboxes(messageId, ImmutableList.of(aliceMailbox1.getMailboxId(), aliceMailbox2.getMailboxId()), aliceSession); + + messageIdManager.delete(messageId, aliceSession); + + assertThat(messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.MINIMAL, aliceSession)).isEmpty(); + } + + @Test public void deleteMessageShouldNotRemoveMessageOnAnotherMailbox() throws Exception { MessageId messageId = testingData.persist(aliceMailbox1.getMailboxId(), messageUid1, FLAGS, aliceSession); @@ -311,6 +333,14 @@ public abstract class AbstractMessageIdManagerStorageTest { } @Test + public void deleteAllShouldReturnNotFoundWhenDeletingOnOtherSession() throws Exception { + MessageId messageId = testingData.persist(aliceMailbox1.getMailboxId(), messageUid1, FLAGS, aliceSession); + + assertThat(messageIdManager.delete(messageId, bobSession)) + .isEqualTo(DeleteResult.notFound(messageId)); + } + + @Test public void deleteMessageShouldThrowExceptionWhenDeletingOnSystemSession() throws Exception { expectedException.expect(MailboxNotFoundException.class); http://git-wip-us.apache.org/repos/asf/james-project/blob/5bfbc370/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java index 054c44a..badf740 100644 --- a/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java +++ b/mailbox/store/src/test/java/org/apache/james/mailbox/store/mail/model/MessageIdMapperTest.java @@ -30,6 +30,7 @@ import javax.mail.Flags; import javax.mail.Flags.Flag; import javax.mail.util.SharedByteArrayInputStream; +import org.apache.commons.lang3.tuple.Pair; import org.apache.james.mailbox.FlagsBuilder; import org.apache.james.mailbox.MessageManager.FlagsUpdateMode; import org.apache.james.mailbox.exception.MailboxException; @@ -52,7 +53,9 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import com.github.steveash.guavate.Guavate; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMultimap; public abstract class MessageIdMapperTest { @@ -880,6 +883,79 @@ public abstract class MessageIdMapperTest { assertThat(messageMapper.countUnseenMessagesInMailbox(benwaInboxMailbox)).isEqualTo(1); } + @Test + public void deletesShouldOnlyRemoveConcernedMessages() throws Exception { + saveMessages(); + + SimpleMailboxMessage copiedMessage = SimpleMailboxMessage.copy(benwaWorkMailbox.getMailboxId(), message1); + copiedMessage.setUid(mapperProvider.generateMessageUid()); + copiedMessage.setModSeq(mapperProvider.generateModSeq(benwaWorkMailbox)); + sut.copyInMailbox(copiedMessage); + + sut.delete( + ImmutableMultimap.<MessageId, MailboxId>builder() + .put(message1.getMessageId(), benwaWorkMailbox.getMailboxId()) + .put(message2.getMessageId(), benwaInboxMailbox.getMailboxId()) + .build()); + + ImmutableList<Pair<MessageId, MailboxId>> storedMessages = + sut.find(ImmutableList.of(message1.getMessageId(), message2.getMessageId()), FetchType.Metadata) + .stream() + .map(message -> Pair.of(message.getMessageId(), message.getMailboxId())) + .collect(Guavate.toImmutableList()); + + assertThat(storedMessages) + .containsOnly(Pair.of(message1.getMessageId(), benwaInboxMailbox.getMailboxId())); + } + + @Test + public void deletesShouldUpdateMessageCount() throws Exception { + saveMessages(); + + SimpleMailboxMessage copiedMessage = SimpleMailboxMessage.copy(benwaWorkMailbox.getMailboxId(), message1); + copiedMessage.setUid(mapperProvider.generateMessageUid()); + copiedMessage.setModSeq(mapperProvider.generateModSeq(benwaWorkMailbox)); + sut.copyInMailbox(copiedMessage); + + sut.delete( + ImmutableMultimap.<MessageId, MailboxId>builder() + .put(message1.getMessageId(), benwaWorkMailbox.getMailboxId()) + .put(message2.getMessageId(), benwaInboxMailbox.getMailboxId()) + .build()); + + assertThat(messageMapper.countMessagesInMailbox(benwaInboxMailbox)) + .isEqualTo(2); + } + + @Test + public void deletesShouldUpdateUnreadCount() throws Exception { + message1.setUid(mapperProvider.generateMessageUid()); + message1.setModSeq(mapperProvider.generateModSeq(benwaInboxMailbox)); + message1.setFlags(new Flags(Flag.SEEN)); + sut.save(message1); + + message2.setUid(mapperProvider.generateMessageUid()); + message2.setModSeq(mapperProvider.generateModSeq(benwaInboxMailbox)); + sut.save(message2); + + sut.delete( + ImmutableMultimap.<MessageId, MailboxId>builder() + .put(message1.getMessageId(), benwaInboxMailbox.getMailboxId()) + .put(message2.getMessageId(), benwaInboxMailbox.getMailboxId()) + .build()); + + assertThat(messageMapper.countUnseenMessagesInMailbox(benwaInboxMailbox)) + .isEqualTo(0); + } + + @Test + public void deletesShouldNotFailUponMissingMessage() { + sut.delete( + ImmutableMultimap.<MessageId, MailboxId>builder() + .put(message1.getMessageId(), benwaWorkMailbox.getMailboxId()) + .build()); + } + private SimpleMailbox createMailbox(MailboxPath mailboxPath) throws MailboxException { SimpleMailbox mailbox = new SimpleMailbox(mailboxPath, UID_VALIDITY); mailbox.setMailboxId(mapperProvider.generateId()); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
