blob: 55d00f4c21521847da2e26636c1ad050812df41c [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;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.SoftAssertions.assertSoftly;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import javax.mail.Flags;
import org.apache.james.core.Username;
import org.apache.james.core.quota.QuotaCountLimit;
import org.apache.james.core.quota.QuotaCountUsage;
import org.apache.james.core.quota.QuotaSizeLimit;
import org.apache.james.core.quota.QuotaSizeUsage;
import org.apache.james.mailbox.MailboxManager.MailboxCapabilities;
import org.apache.james.mailbox.MessageManager.AppendCommand;
import org.apache.james.mailbox.events.EventBus;
import org.apache.james.mailbox.events.MailboxIdRegistrationKey;
import org.apache.james.mailbox.events.MailboxListener;
import org.apache.james.mailbox.events.MessageMoveEvent;
import org.apache.james.mailbox.exception.AnnotationException;
import org.apache.james.mailbox.exception.HasEmptyMailboxNameInHierarchyException;
import org.apache.james.mailbox.exception.InboxAlreadyCreated;
import org.apache.james.mailbox.exception.MailboxException;
import org.apache.james.mailbox.exception.MailboxNotFoundException;
import org.apache.james.mailbox.exception.TooLongMailboxNameException;
import org.apache.james.mailbox.extension.PreDeletionHook;
import org.apache.james.mailbox.mock.DataProvisioner;
import org.apache.james.mailbox.model.ComposedMessageId;
import org.apache.james.mailbox.model.FetchGroup;
import org.apache.james.mailbox.model.MailboxACL;
import org.apache.james.mailbox.model.MailboxAnnotation;
import org.apache.james.mailbox.model.MailboxAnnotationKey;
import org.apache.james.mailbox.model.MailboxCounters;
import org.apache.james.mailbox.model.MailboxId;
import org.apache.james.mailbox.model.MailboxMetaData;
import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.MessageId;
import org.apache.james.mailbox.model.MessageRange;
import org.apache.james.mailbox.model.MessageResult;
import org.apache.james.mailbox.model.MessageResultIterator;
import org.apache.james.mailbox.model.MultimailboxesSearchQuery;
import org.apache.james.mailbox.model.Quota;
import org.apache.james.mailbox.model.QuotaRoot;
import org.apache.james.mailbox.model.SearchQuery;
import org.apache.james.mailbox.model.search.MailboxQuery;
import org.apache.james.mailbox.util.EventCollector;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.util.ClassLoaderUtils;
import org.apache.james.util.concurrency.ConcurrentTestRunner;
import org.assertj.core.api.SoftAssertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import com.github.fge.lambdas.Throwing;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import reactor.core.publisher.Mono;
/**
* Test the {@link MailboxManager} methods that
* are not covered by the protocol-tester suite.
*
* This class needs to be extended by the different mailbox
* implementations which are responsible to setup and
* implement the test methods.
*
*/
public abstract class MailboxManagerTest<T extends MailboxManager> {
public static final Username USER_1 = Username.of("USER_1");
public static final Username USER_2 = Username.of("USER_2");
private static final int DEFAULT_MAXIMUM_LIMIT = 256;
private T mailboxManager;
private MailboxSession session;
private Message.Builder message;
private PreDeletionHook preDeletionHook1;
private PreDeletionHook preDeletionHook2;
protected abstract T provideMailboxManager();
protected abstract EventBus retrieveEventBus(T mailboxManager);
protected Set<PreDeletionHook> preDeletionHooks() {
return ImmutableSet.of(preDeletionHook1, preDeletionHook2);
}
@BeforeEach
void setUp() throws Exception {
setupMockForPreDeletionHooks();
this.mailboxManager = provideMailboxManager();
this.message = Message.Builder.of()
.setSubject("test")
.setBody("testmail", StandardCharsets.UTF_8);
}
private void setupMockForPreDeletionHooks() {
preDeletionHook1 = mock(PreDeletionHook.class);
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
.thenReturn(Mono.empty());
preDeletionHook2 = mock(PreDeletionHook.class);
when(preDeletionHook2.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
.thenReturn(Mono.empty());
}
@AfterEach
void tearDown() {
mailboxManager.logout(session);
mailboxManager.endProcessingRequest(session);
}
@Test
protected void creatingConcurrentlyMailboxesWithSameParentShouldNotFail() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z";
ConcurrentTestRunner.builder()
.operation((a, b) -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName + a), session))
.threadCount(10)
.runSuccessfullyWithin(Duration.ofMinutes(1));
}
@Test
void createMailboxShouldReturnRightId() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "name.subfolder");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
MessageManager retrievedMailbox = mailboxManager.getMailbox(mailboxPath, session);
assertThat(mailboxId.isPresent()).isTrue();
assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
}
@Nested
class MailboxCreationTests {
@Test
void hasInboxShouldBeFalseWhenINBOXIsNotCreated() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
assertThat(mailboxManager.hasInbox(session)).isFalse();
}
@Test
void hasInboxShouldBeTrueWhenINBOXIsCreated() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath mailboxPath = MailboxPath.inbox(session);
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
MessageManager retrievedMailbox = mailboxManager.getMailbox(mailboxPath, session);
assertThat(mailboxManager.hasInbox(session)).isTrue();
assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
}
@Test
void creatingMixedCaseINBOXShouldCreateItAsINBOX() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(MailboxPath.forUser(USER_1, "iNbOx"), session);
MessageManager retrievedMailbox = mailboxManager.getMailbox(MailboxPath.inbox(session), session);
assertThat(mailboxManager.hasInbox(session)).isTrue();
assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
}
@Test
void creatingMixedCaseINBOXShouldNotBeRetrievableAsIt() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "iNbOx");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
assertThat(mailboxId).isPresent();
assertThatThrownBy(() -> mailboxManager.getMailbox(mailboxPath, session))
.isInstanceOf(MailboxNotFoundException.class);
}
@Test
void creatingMixedCaseINBOXWhenItHasAlreadyBeenCreatedShouldThrow() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
mailboxManager.createMailbox(MailboxPath.inbox(session), session);
assertThatThrownBy(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, "iNbOx"), session))
.isInstanceOf(InboxAlreadyCreated.class);
}
@Test
void creatingMixedCaseINBOXShouldCreateItAsINBOXUponChildMailboxCreation() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(MailboxPath.forUser(USER_1, "iNbOx.submailbox"), session);
MessageManager retrievedMailbox = mailboxManager.getMailbox(MailboxPath.inbox(session), session);
assertThat(mailboxManager.hasInbox(session)).isTrue();
}
@Test
void creatingMixedCaseINBOXChildShouldNormalizeChildPath() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath childPath = MailboxPath.forUser(USER_1, "iNbOx.submailbox");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(childPath, session);
MessageManager retrievedMailbox = mailboxManager.getMailbox(childPath, session);
assertThat(mailboxManager.hasInbox(session)).isTrue();
assertThat(mailboxId.get()).isEqualTo(retrievedMailbox.getId());
}
}
@Nested
public class MailboxNameLimitTests {
@Test
void creatingMailboxShouldNotFailWhenLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH);
assertThatCode(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.doesNotThrowAnyException();
}
@Test
void renamingMailboxShouldNotFailWhenLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH);
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatCode(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session))
.doesNotThrowAnyException();
}
@Test
protected void renamingMailboxByIdShouldNotFailWhenLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH);
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatCode(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session))
.doesNotThrowAnyException();
}
@Test
void creatingMailboxShouldThrowWhenOverLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH + 1);
assertThatThrownBy(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(TooLongMailboxNameException.class);
}
@Test
void renamingMailboxShouldThrowWhenOverLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH + 1);
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(TooLongMailboxNameException.class);
}
@Test
void renamingMailboxByIdShouldThrowWhenOverLimitNameLength() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = Strings.repeat("a", MailboxManager.MAX_MAILBOX_NAME_LENGTH + 1);
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(TooLongMailboxNameException.class);
}
@Test
void creatingMailboxShouldNotThrowWhenNameWithoutEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.c";
assertThatCode(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session)).doesNotThrowAnyException();
}
@Test
void creatingMailboxShouldNotThrowWhenNameWithASingleToBeNormalizedTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.";
assertThatCode(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.doesNotThrowAnyException();
}
@Test
void creatingMailboxShouldThrowWhenNameWithMoreThanOneTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..";
assertThatThrownBy(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void creatingMailboxShouldThrowWhenNameWithHeadingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = ".a";
assertThatThrownBy(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void creatingMailboxShouldThrowWhenNameWithEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..b";
assertThatThrownBy(() -> mailboxManager.createMailbox(MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxShouldNotThrowWhenNameWithoutEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.c";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatCode(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session)).doesNotThrowAnyException();
}
@Test
protected void renamingMailboxByIdShouldNotThrowWhenNameWithoutEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.c";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatCode(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session)).doesNotThrowAnyException();
}
@Test
void renamingMailboxShouldNotThrowWhenNameWithASingleToBeNormalizedTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatCode(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session)).doesNotThrowAnyException();
}
@Test
protected void renamingMailboxByIdShouldNotThrowWhenNameWithASingleToBeNormalizedTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a.b.";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatCode(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session)).doesNotThrowAnyException();
}
@Test
void renamingMailboxShouldThrowWhenNameWithMoreThanOneTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxByIdShouldThrowWhenNameWithMoreThanOneTrailingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxShouldThrowWhenNameWithHeadingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = ".a";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxByIdShouldThrowWhenNameWithHeadingDelimiter() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = ".a";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxShouldThrowWhenNameWithEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..b";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
mailboxManager.createMailbox(originPath, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(originPath, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
@Test
void renamingMailboxByIdShouldThrowWhenNameWithEmptyHierarchicalLevel() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
String mailboxName = "a..b";
MailboxPath originPath = MailboxPath.forUser(USER_1, "origin");
MailboxId mailboxId = mailboxManager.createMailbox(originPath, session).get();
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId, MailboxPath.forUser(USER_1, mailboxName), session))
.isInstanceOf(HasEmptyMailboxNameInHierarchyException.class);
}
}
@Nested
class AnnotationTests {
private final MailboxAnnotationKey privateKey = new MailboxAnnotationKey("/private/comment");
private final MailboxAnnotationKey privateChildKey = new MailboxAnnotationKey("/private/comment/user");
private final MailboxAnnotationKey privateGrandchildKey = new MailboxAnnotationKey("/private/comment/user/name");
private final MailboxAnnotationKey sharedKey = new MailboxAnnotationKey("/shared/comment");
private final MailboxAnnotation privateAnnotation = MailboxAnnotation.newInstance(privateKey, "My private comment");
private final MailboxAnnotation privateChildAnnotation = MailboxAnnotation.newInstance(privateChildKey, "My private comment");
private final MailboxAnnotation privateGrandchildAnnotation = MailboxAnnotation.newInstance(privateGrandchildKey, "My private comment");
private final MailboxAnnotation privateAnnotationUpdate = MailboxAnnotation.newInstance(privateKey, "My updated private comment");
private final MailboxAnnotation sharedAnnotation = MailboxAnnotation.newInstance(sharedKey, "My shared comment");
private final List<MailboxAnnotation> annotations = ImmutableList.of(privateAnnotation, sharedAnnotation);
@Test
void updateAnnotationsShouldUpdateStoredAnnotation() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotation));
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotationUpdate));
assertThat(mailboxManager.getAllAnnotations(inbox, session)).containsOnly(privateAnnotationUpdate);
}
@Test
void updateAnnotationsShouldDeleteAnnotationWithNilValue() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotation));
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(MailboxAnnotation.nil(privateKey)));
assertThat(mailboxManager.getAllAnnotations(inbox, session)).isEmpty();
}
@Test
void updateAnnotationsShouldThrowExceptionIfMailboxDoesNotExist() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
assertThatThrownBy(() -> mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotation)))
.isInstanceOf(MailboxException.class);
}
@Test
void getAnnotationsShouldReturnEmptyForNonStoredAnnotation() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThat(mailboxManager.getAllAnnotations(inbox, session)).isEmpty();
}
@Test
void getAllAnnotationsShouldRetrieveStoredAnnotations() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, annotations);
assertThat(mailboxManager.getAllAnnotations(inbox, session)).isEqualTo(annotations);
}
@Test
void getAllAnnotationsShouldThrowExceptionIfMailboxDoesNotExist() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
assertThatThrownBy(() -> mailboxManager.getAllAnnotations(inbox, session))
.isInstanceOf(MailboxException.class);
}
@Test
void getAnnotationsByKeysShouldRetrieveStoresAnnotationsByKeys() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, annotations);
assertThat(mailboxManager.getAnnotationsByKeys(inbox, session, ImmutableSet.of(privateKey)))
.containsOnly(privateAnnotation);
}
@Test
void getAnnotationsByKeysShouldThrowExceptionIfMailboxDoesNotExist() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
assertThatThrownBy(() -> mailboxManager.getAnnotationsByKeys(inbox, session, ImmutableSet.of(privateKey)))
.isInstanceOf(MailboxException.class);
}
@Test
void getAnnotationsByKeysWithOneDepthShouldRetriveAnnotationsWithOneDepth() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotation, privateChildAnnotation, privateGrandchildAnnotation));
assertThat(mailboxManager.getAnnotationsByKeysWithOneDepth(inbox, session, ImmutableSet.of(privateKey)))
.contains(privateAnnotation, privateChildAnnotation);
}
@Test
void getAnnotationsByKeysWithAllDepthShouldThrowExceptionWhenMailboxDoesNotExist() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
assertThatThrownBy(() -> mailboxManager.getAnnotationsByKeysWithAllDepth(inbox, session, ImmutableSet.of(privateKey)))
.isInstanceOf(MailboxException.class);
}
@Test
void getAnnotationsByKeysWithAllDepthShouldRetriveAnnotationsWithAllDepth() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(privateAnnotation, privateChildAnnotation, privateGrandchildAnnotation));
assertThat(mailboxManager.getAnnotationsByKeysWithAllDepth(inbox, session, ImmutableSet.of(privateKey)))
.contains(privateAnnotation, privateChildAnnotation, privateGrandchildAnnotation);
}
@Test
void updateAnnotationsShouldThrowExceptionIfAnnotationDataIsOverLimitation() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThatThrownBy(() -> mailboxManager.updateAnnotations(inbox, session, ImmutableList.of(MailboxAnnotation.newInstance(privateKey, "The limitation of data is less than 30"))))
.isInstanceOf(AnnotationException.class);
}
@Test
void shouldUpdateAnnotationWhenRequestCreatesNewAndMailboxIsNotOverLimit() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
ImmutableList.Builder<MailboxAnnotation> builder = ImmutableList.builder();
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment1"), "AnyValue"));
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment2"), "AnyValue"));
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment3"), "AnyValue"));
mailboxManager.updateAnnotations(inbox, session, builder.build());
}
@Test
void updateAnnotationsShouldThrowExceptionIfRequestCreateNewButMailboxIsOverLimit() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Annotation));
session = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
ImmutableList.Builder<MailboxAnnotation> builder = ImmutableList.builder();
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment1"), "AnyValue"));
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment2"), "AnyValue"));
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment3"), "AnyValue"));
builder.add(MailboxAnnotation.newInstance(new MailboxAnnotationKey("/private/comment4"), "AnyValue"));
assertThatThrownBy(() -> mailboxManager.updateAnnotations(inbox, session, builder.build()))
.isInstanceOf(MailboxException.class);
}
}
@Nested
class EventTests {
private final QuotaRoot quotaRoot = QuotaRoot.quotaRoot("#private&user_1", Optional.empty());
private EventCollector listener;
private MailboxPath inbox;
private MailboxId inboxId;
private MessageManager inboxManager;
private MailboxPath newPath;
@BeforeEach
void setUp() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
inbox = MailboxPath.inbox(session);
newPath = MailboxPath.forUser(USER_1, "specialMailbox");
listener = new EventCollector();
inboxId = mailboxManager.createMailbox(inbox, session).get();
inboxManager = mailboxManager.getMailbox(inbox, session);
}
@Test
void deleteMailboxShouldFireMailboxDeletionEvent() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Quota));
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
mailboxManager.deleteMailbox(inbox, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.MailboxDeletion)
.hasSize(1)
.extracting(event -> (MailboxListener.MailboxDeletion) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
.satisfies(event -> assertThat(event.getDeletedMessageCount()).isEqualTo(QuotaCountUsage.count(0)))
.satisfies(event -> assertThat(event.getTotalDeletedSize()).isEqualTo(QuotaSizeUsage.size(0)));
}
@Test
void deleteMailboxByIdShouldFireMailboxDeletionEvent() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Quota));
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
mailboxManager.deleteMailbox(inboxId, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.MailboxDeletion)
.hasSize(1)
.extracting(event -> (MailboxListener.MailboxDeletion) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
.satisfies(event -> assertThat(event.getDeletedMessageCount()).isEqualTo(QuotaCountUsage.count(0)))
.satisfies(event -> assertThat(event.getTotalDeletedSize()).isEqualTo(QuotaSizeUsage.size(0)));
}
@Test
void createMailboxShouldFireMailboxAddedEvent() throws Exception {
retrieveEventBus(mailboxManager).register(listener);
Optional<MailboxId> newId = mailboxManager.createMailbox(newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.MailboxAdded)
.hasSize(1)
.extracting(event -> (MailboxListener.MailboxAdded) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(newId.get()));
}
@Test
void addingMessageShouldFireQuotaUpdateEvent() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Quota));
retrieveEventBus(mailboxManager).register(listener);
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(message), session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.QuotaUsageUpdatedEvent)
.hasSize(1)
.extracting(event -> (MailboxListener.QuotaUsageUpdatedEvent) event)
.element(0)
.satisfies(event -> assertThat(event.getQuotaRoot()).isEqualTo(quotaRoot))
.satisfies(event -> assertThat(event.getSizeQuota()).isEqualTo(Quota.<QuotaSizeLimit, QuotaSizeUsage>builder()
.used(QuotaSizeUsage.size(85))
.computedLimit(QuotaSizeLimit.unlimited())
.build()))
.satisfies(event -> assertThat(event.getCountQuota()).isEqualTo(Quota.<QuotaCountLimit, QuotaCountUsage>builder()
.used(QuotaCountUsage.count(1))
.computedLimit(QuotaCountLimit.unlimited())
.build()));
}
@Test
void addingMessageShouldFireAddedEvent() throws Exception {
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
inboxManager.appendMessage(MessageManager.AppendCommand.builder()
.build(message), session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Added)
.hasSize(1)
.extracting(event -> (MailboxListener.Added) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void expungeMessageShouldFireExpungedEvent() throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder().build(message), session);
inboxManager.setFlags(new Flags(Flags.Flag.DELETED), MessageManager.FlagsUpdateMode.ADD, MessageRange.all(), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
inboxManager.expunge(MessageRange.all(), session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Expunged)
.hasSize(1)
.extracting(event -> (MailboxListener.Expunged) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void deleteMessageShouldFireExpungedEvent() throws Exception {
ComposedMessageId messageId = inboxManager.appendMessage(MessageManager.AppendCommand.builder().build(message), session);
inboxManager.setFlags(new Flags(Flags.Flag.DELETED), MessageManager.FlagsUpdateMode.ADD, MessageRange.all(), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
inboxManager.delete(ImmutableList.of(messageId.getUid()), session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Expunged)
.hasSize(1)
.extracting(event -> (MailboxListener.Expunged) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void setFlagsShouldFireFlagsUpdatedEvent() throws Exception {
inboxManager.appendMessage(MessageManager.AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
inboxManager.setFlags(new Flags(Flags.Flag.FLAGGED), MessageManager.FlagsUpdateMode.ADD, MessageRange.all(), session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.FlagsUpdated)
.hasSize(1)
.extracting(event -> (MailboxListener.FlagsUpdated) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void moveShouldFireAddedEventInTargetMailbox() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Move));
Optional<MailboxId> targetMailboxId = mailboxManager.createMailbox(newPath, session);
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(targetMailboxId.get()));
mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Added)
.hasSize(1)
.extracting(event -> (MailboxListener.Added) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(targetMailboxId.get()))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void moveShouldFireExpungedEventInOriginMailbox() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Move));
mailboxManager.createMailbox(newPath, session);
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Expunged)
.hasSize(1)
.extracting(event -> (MailboxListener.Expunged) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(inboxId))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void copyShouldFireAddedEventInTargetMailbox() throws Exception {
Optional<MailboxId> targetMailboxId = mailboxManager.createMailbox(newPath, session);
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(targetMailboxId.get()));
mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Added)
.hasSize(1)
.extracting(event -> (MailboxListener.Added) event)
.element(0)
.satisfies(event -> assertThat(event.getMailboxId()).isEqualTo(targetMailboxId.get()))
.satisfies(event -> assertThat(event.getUids()).hasSize(1));
}
@Test
void copyShouldFireMovedEventInTargetMailbox() throws Exception {
assumeTrue(mailboxManager.getSupportedMessageCapabilities().contains(MailboxManager.MessageCapabilities.UniqueID));
Optional<MailboxId> targetMailboxId = mailboxManager.createMailbox(newPath, session);
ComposedMessageId messageId = inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(targetMailboxId.get()));
mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MessageMoveEvent)
.hasSize(1)
.extracting(event -> (MessageMoveEvent) event)
.element(0)
.satisfies(event -> assertThat(event.getMessageIds()).containsExactly(messageId.getMessageId()));
}
@Test
void copyShouldNotFireMovedEventInOriginMailbox() throws Exception {
assumeTrue(mailboxManager.getSupportedMessageCapabilities().contains(MailboxManager.MessageCapabilities.UniqueID));
mailboxManager.createMailbox(newPath, session);
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MessageMoveEvent)
.isEmpty();;
}
@Test
void moveShouldFireMovedEventInTargetMailbox() throws Exception {
assumeTrue(mailboxManager.getSupportedMessageCapabilities().contains(MailboxManager.MessageCapabilities.UniqueID));
Optional<MailboxId> targetMailboxId = mailboxManager.createMailbox(newPath, session);
ComposedMessageId messageId = inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(targetMailboxId.get()));
mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MessageMoveEvent)
.hasSize(1)
.extracting(event -> (MessageMoveEvent) event)
.element(0)
.satisfies(event -> assertThat(event.getMessageIds()).containsExactly(messageId.getMessageId()));
}
@Test
void moveShouldFireMovedEventInOriginMailbox() throws Exception {
assumeTrue(mailboxManager.getSupportedMessageCapabilities().contains(MailboxManager.MessageCapabilities.UniqueID));
mailboxManager.createMailbox(newPath, session);
ComposedMessageId messageId = inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener, new MailboxIdRegistrationKey(inboxId));
mailboxManager.moveMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MessageMoveEvent)
.hasSize(1)
.extracting(event -> (MessageMoveEvent) event)
.element(0)
.satisfies(event -> assertThat(event.getMessageIds()).containsExactly(messageId.getMessageId()));
}
@Test
void copyShouldNotFireExpungedEventInOriginMailbox() throws Exception {
mailboxManager.createMailbox(newPath, session);
inboxManager.appendMessage(AppendCommand.builder().build(message), session);
retrieveEventBus(mailboxManager).register(listener);
mailboxManager.copyMessages(MessageRange.all(), inbox, newPath, session);
assertThat(listener.getEvents())
.filteredOn(event -> event instanceof MailboxListener.Expunged)
.isEmpty();
}
}
@Nested
class SearchTests {
@Test
void searchShouldNotReturnResultsFromOtherNamespaces() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Namespace));
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.createMailbox(new MailboxPath("other_namespace", USER_1, "Other"), session);
mailboxManager.createMailbox(MailboxPath.inbox(session), session);
List<MailboxMetaData> metaDatas = mailboxManager.search(
MailboxQuery.privateMailboxesBuilder(session)
.matchesAllMailboxNames()
.build(),
session);
assertThat(metaDatas).hasSize(1);
assertThat(metaDatas.get(0).getPath()).isEqualTo(MailboxPath.inbox(session));
}
@Test
void searchShouldReturnACL() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Namespace));
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
Optional<MailboxId> inboxId = mailboxManager.createMailbox(MailboxPath.inbox(session), session);
MailboxACL acl = MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition());
mailboxManager.setRights(inboxId.get(), acl, session);
List<MailboxMetaData> metaDatas = mailboxManager.search(
MailboxQuery.privateMailboxesBuilder(session)
.matchesAllMailboxNames()
.build(),
session);
assertThat(metaDatas)
.hasSize(1)
.first()
.extracting(MailboxMetaData::getResolvedAcls)
.isEqualTo(acl.apply(MailboxACL.command()
.forOwner()
.rights(MailboxACL.Rfc4314Rights.allExcept())
.asAddition()));
}
@Test
void searchShouldNotReturnResultsFromOtherUsers() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
mailboxManager.createMailbox(MailboxPath.forUser(USER_2, "Other"), session2);
mailboxManager.createMailbox(MailboxPath.inbox(session), session);
List<MailboxMetaData> metaDatas = mailboxManager.search(
MailboxQuery.privateMailboxesBuilder(session)
.matchesAllMailboxNames()
.build(),
session);
assertThat(metaDatas).hasSize(1);
assertThat(metaDatas.get(0).getPath()).isEqualTo(MailboxPath.inbox(session));
}
@Test
void searchShouldNotDuplicateMailboxWhenReportedAsUserMailboxesAndUserHasRightOnMailboxes() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox1 = MailboxPath.inbox(session1);
mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_1)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session1))
.extracting(MailboxMetaData::getPath)
.hasSize(1)
.containsOnly(inbox1);
}
@Test
void searchShouldIncludeDelegatedMailboxes() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
Optional<MailboxId> mailboxIdInbox1 = mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Lookup)
.asAddition()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session2))
.extracting(MailboxMetaData::getPath)
.containsOnly(inbox1);
}
@Test
void searchShouldCombinePrivateAndDelegatedMailboxes() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
MailboxPath inbox2 = MailboxPath.inbox(session2);
mailboxManager.createMailbox(inbox1, session1);
mailboxManager.createMailbox(inbox2, session2);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session2))
.extracting(MailboxMetaData::getPath)
.containsOnly(inbox1, inbox2);
}
@Test
void searchShouldAllowUserFiltering() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
MailboxPath inbox2 = MailboxPath.inbox(session2);
mailboxManager.createMailbox(inbox1, session1);
mailboxManager.createMailbox(inbox2, session2);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.username(USER_1)
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session2))
.extracting(MailboxMetaData::getPath)
.containsOnly(inbox1);
}
@Test
void searchShouldAllowNamespaceFiltering() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
String specificNamespace = "specificNamespace";
MailboxPath mailboxPath1 = new MailboxPath(specificNamespace, USER_1, "mailbox");
mailboxManager.createMailbox(inbox1, session1);
mailboxManager.createMailbox(mailboxPath1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
mailboxManager.setRights(mailboxPath1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.namespace(specificNamespace)
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session2))
.extracting(MailboxMetaData::getPath)
.containsOnly(mailboxPath1);
}
@Test
void searchForMessageShouldReturnMessagesFromAllMyMailboxesIfNoMailboxesAreSpecified() throws Exception {
assumeTrue(mailboxManager
.getSupportedMessageCapabilities()
.contains(MailboxManager.MessageCapabilities.UniqueID));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath cacahueteFolder = MailboxPath.forUser(USER_1, "CACAHUETE");
MailboxId cacahueteMailboxId = mailboxManager.createMailbox(cacahueteFolder, session).get();
MessageManager cacahueteMessageManager = mailboxManager.getMailbox(cacahueteMailboxId, session);
MessageId cacahueteMessageId = cacahueteMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MailboxPath pirouetteFilder = MailboxPath.forUser(USER_1, "PIROUETTE");
MailboxId pirouetteMailboxId = mailboxManager.createMailbox(pirouetteFilder, session).get();
MessageManager pirouetteMessageManager = mailboxManager.getMailbox(pirouetteMailboxId, session);
MessageId pirouetteMessageId = pirouetteMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsOnly(cacahueteMessageId, pirouetteMessageId);
}
@Test
void searchForMessageShouldReturnMessagesFromMyDelegatedMailboxes() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionFromDelegater = mailboxManager.createSystemSession(USER_2);
MailboxPath delegatedMailboxPath = MailboxPath.forUser(USER_2, "SHARED");
MailboxId delegatedMailboxId = mailboxManager.createMailbox(delegatedMailboxPath, sessionFromDelegater).get();
MessageManager delegatedMessageManager = mailboxManager.getMailbox(delegatedMailboxId, sessionFromDelegater);
MessageId messageId = delegatedMessageManager
.appendMessage(AppendCommand.from(message), sessionFromDelegater)
.getMessageId();
mailboxManager.setRights(delegatedMailboxPath,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_1)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
sessionFromDelegater);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsOnly(messageId);
}
@Test
void searchForMessageShouldNotReturnMessagesFromMyDelegatedMailboxesICanNotRead() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionFromDelegater = mailboxManager.createSystemSession(USER_2);
MailboxPath delegatedMailboxPath = MailboxPath.forUser(USER_2, "SHARED");
MailboxId delegatedMailboxId = mailboxManager.createMailbox(delegatedMailboxPath, sessionFromDelegater).get();
MessageManager delegatedMessageManager = mailboxManager.getMailbox(delegatedMailboxId, sessionFromDelegater);
delegatedMessageManager.appendMessage(AppendCommand.from(message), sessionFromDelegater);
mailboxManager.setRights(delegatedMailboxPath,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_1)
.rights(MailboxACL.Right.Lookup)
.asAddition()),
sessionFromDelegater);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
}
@Test
void searchForMessageShouldOnlySearchInMailboxICanRead() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionFromDelegater = mailboxManager.createSystemSession(USER_2);
MailboxPath otherMailboxPath = MailboxPath.forUser(USER_2, "OTHER_MAILBOX");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailboxPath, sessionFromDelegater).get();
MessageManager otherMailboxManager = mailboxManager.getMailbox(otherMailboxId, sessionFromDelegater);
otherMailboxManager.appendMessage(AppendCommand.from(message), sessionFromDelegater);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
}
@Test
void searchForMessageShouldIgnoreMailboxThatICanNotRead() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionFromDelegater = mailboxManager.createSystemSession(USER_2);
MailboxPath otherMailboxPath = MailboxPath.forUser(USER_2, "SHARED");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailboxPath, sessionFromDelegater).get();
MessageManager otherMessageManager = mailboxManager.getMailbox(otherMailboxId, sessionFromDelegater);
otherMessageManager.appendMessage(AppendCommand.from(message), sessionFromDelegater);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
}
@Test
void searchForMessageShouldCorrectlyExcludeMailbox() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath otherMailboxPath = MailboxPath.forUser(USER_1, "SHARED");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailboxPath, session).get();
MessageManager otherMessageManager = mailboxManager.getMailbox(otherMailboxId, session);
otherMessageManager.appendMessage(AppendCommand.from(message), session);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.notInMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
}
@Test
void searchForMessageShouldPriorizeExclusionFromInclusion() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath otherMailboxPath = MailboxPath.forUser(USER_1, "SHARED");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailboxPath, session).get();
MessageManager otherMessageManager = mailboxManager.getMailbox(otherMailboxId, session);
otherMessageManager.appendMessage(AppendCommand.from(message), session);
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.notInMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
}
@Test
void searchForMessageShouldOnlySearchInGivenMailbox() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath searchedMailboxPath = MailboxPath.forUser(USER_1, "WANTED");
MailboxId searchedMailboxId = mailboxManager.createMailbox(searchedMailboxPath, session).get();
MessageManager searchedMessageManager = mailboxManager.getMailbox(searchedMailboxId, session);
MailboxPath otherMailboxPath = MailboxPath.forUser(USER_1, "SHARED");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailboxPath, session).get();
MessageManager otherMessageManager = mailboxManager.getMailbox(otherMailboxId, session);
otherMessageManager.appendMessage(AppendCommand.from(message), session);
MessageId messageId = searchedMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MultimailboxesSearchQuery multiMailboxesQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(searchedMailboxId)
.build();
assertThat(mailboxManager.search(multiMailboxesQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId);
}
@Test
void searchShouldNotReturnNoMoreDelegatedMailboxes() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
Optional<MailboxId> mailboxIdInbox1 = mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asAddition()),
session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Read, MailboxACL.Right.Lookup)
.asRemoval()),
session1);
MailboxQuery mailboxQuery = MailboxQuery.builder()
.matchesAllMailboxNames()
.build();
assertThat(mailboxManager.search(mailboxQuery, session2))
.isEmpty();
}
}
@Nested
class MetadataTests {
@Test
void getMailboxCountersShouldReturnDefaultValueWhenNoReadRight() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
Optional<MailboxId> mailboxIdInbox1 = mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Lookup)
.asAddition()),
session1);
mailboxManager.getMailbox(inbox1, session1).appendMessage(AppendCommand.from(message), session1);
MailboxCounters mailboxCounters = mailboxManager.getMailbox(inbox1, session2)
.getMailboxCounters(session2);
assertThat(mailboxCounters)
.isEqualTo(MailboxCounters.builder()
.mailboxId(mailboxIdInbox1.get())
.count(0)
.unseen(0)
.build());
}
@Test
void getMailboxCountersShouldReturnStoredValueWhenReadRight() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
Optional<MailboxId> mailboxIdInbox1 = mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Lookup, MailboxACL.Right.Read)
.asAddition()),
session1);
mailboxManager.getMailbox(inbox1, session1)
.appendMessage(AppendCommand.builder()
.recent()
.build(message), session1);
MailboxCounters mailboxCounters = mailboxManager.getMailbox(inbox1, session2)
.getMailboxCounters(session2);
assertThat(mailboxCounters)
.isEqualTo(MailboxCounters.builder()
.mailboxId(mailboxIdInbox1.get())
.count(1)
.unseen(1)
.build());
}
@Test
@SuppressWarnings("unchecked")
void getMetaDataShouldReturnDefaultValueWhenNoReadRight() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
MailboxSession session1 = mailboxManager.createSystemSession(USER_1);
MailboxSession session2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(session1);
mailboxManager.createMailbox(inbox1, session1);
mailboxManager.setRights(inbox1,
MailboxACL.EMPTY.apply(MailboxACL.command()
.forUser(USER_2)
.rights(MailboxACL.Right.Lookup)
.asAddition()),
session1);
mailboxManager.getMailbox(inbox1, session1)
.appendMessage(AppendCommand.builder()
.recent()
.build(message), session1);
boolean resetRecent = false;
MessageManager.MetaData metaData = mailboxManager.getMailbox(inbox1, session2)
.getMetaData(resetRecent, session2, MessageManager.MetaData.FetchGroup.UNSEEN_COUNT);
assertSoftly(
softly -> {
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getHighestModSeq)
.isEqualTo(ModSeq.first());
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getUidNext)
.isEqualTo(MessageUid.MIN_VALUE);
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getMessageCount)
.isEqualTo(0L);
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getUnseenCount)
.isEqualTo(0L);
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getRecent)
.isEqualTo(ImmutableList.of());
softly.assertThat(metaData)
.extracting(MessageManager.MetaData::getPermanentFlags)
.isEqualTo(new Flags());
});
}
}
@Nested
public class BasicFeaturesTests {
@Test
void user1ShouldNotHaveAnInbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
}
@Test
void user1ShouldBeAbleToCreateInbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
}
@Test
protected void renameMailboxShouldChangeTheMailboxPathOfAMailbox() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx2");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath1, session);
mailboxManager.renameMailbox(mailboxPath1, mailboxPath2, session);
assertThat(mailboxManager.getMailbox(mailboxId.get(), session).getMailboxPath())
.isEqualTo(mailboxPath2);
}
@Test
protected void renameMailboxByIdShouldChangeTheMailboxPathOfAMailbox() throws Exception {
MailboxSession session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx2");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath1, session);
mailboxManager.renameMailbox(mailboxId.get(), mailboxPath2, session);
assertThat(mailboxManager.getMailbox(mailboxId.get(), session).getMailboxPath())
.isEqualTo(mailboxPath2);
}
@Test
void renameMailboxShouldThrowWhenMailboxPathsDoNotBelongToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx2");
mailboxManager.createMailbox(mailboxPath1, sessionUser1);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxPath1, mailboxPath2, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void renameMailboxByIdShouldThrowWhenMailboxPathsDoNotBelongToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_1, "mbx2");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath1, sessionUser1);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId.get(), mailboxPath2, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void renameMailboxShouldThrowWhenFromMailboxPathDoesNotBelongToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_2, "mbx2");
mailboxManager.createMailbox(mailboxPath1, sessionUser1);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxPath1, mailboxPath2, sessionUser2))
.isInstanceOf(MailboxNotFoundException.class);
}
@Test
void renameMailboxByIdShouldThrowWhenFromMailboxPathDoesNotBelongToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_2, "mbx2");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath1, sessionUser1);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId.get(), mailboxPath2, sessionUser2))
.isInstanceOf(MailboxNotFoundException.class);
}
@Test
@Disabled("JAMES-2933 renameMailbox does not assert that user is the owner of destination mailbox")
void renameMailboxShouldThrowWhenToMailboxPathDoesNotBelongToUser() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_2, "mbx2");
mailboxManager.createMailbox(mailboxPath1, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxPath1, mailboxPath2, session))
.isInstanceOf(MailboxNotFoundException.class);
}
@Test
@Disabled("JAMES-2933 renameMailbox does not assert that user is the owner of destination mailbox")
void renameMailboxByIdShouldThrowWhenToMailboxPathDoesNotBelongToUser() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath1 = MailboxPath.forUser(USER_1, "mbx1");
MailboxPath mailboxPath2 = MailboxPath.forUser(USER_2, "mbx2");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath1, session);
assertThatThrownBy(() -> mailboxManager.renameMailbox(mailboxId.get(), mailboxPath2, session))
.isInstanceOf(MailboxNotFoundException.class);
}
@Test
void user1ShouldNotBeAbleToCreateInboxTwice() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThatThrownBy(() -> mailboxManager.createMailbox(inbox, session))
.isInstanceOf(MailboxException.class);
}
@Test
void user1ShouldNotHaveTestSubmailbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThat(mailboxManager.mailboxExists(new MailboxPath(inbox, "INBOX.Test"), session)).isFalse();
}
@Test
void user1ShouldBeAbleToCreateTestSubmailbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
mailboxManager.createMailbox(inboxSubMailbox, session);
assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
}
@Test
void user1ShouldBeAbleToDeleteInbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
mailboxManager.createMailbox(inboxSubMailbox, session);
mailboxManager.deleteMailbox(inbox, session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
}
@Test
protected void user1ShouldBeAbleToDeleteInboxById() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
MailboxId inboxId = mailboxManager.createMailbox(inbox, session).get();
MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
mailboxManager.createMailbox(inboxSubMailbox, session);
mailboxManager.deleteMailbox(inboxId, session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isFalse();
assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isTrue();
}
@Test
void user2ShouldNotBeAbleToDeleteUser1Mailbox() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(sessionUser1);
mailboxManager.createMailbox(inbox, sessionUser1);
assertThatThrownBy(() -> mailboxManager.deleteMailbox(inbox, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void user2ShouldNotBeAbleToDeleteUser1MailboxById() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox = MailboxPath.inbox(sessionUser1);
MailboxId inboxId = mailboxManager.createMailbox(inbox, sessionUser1).get();
assertThatThrownBy(() -> mailboxManager.deleteMailbox(inboxId, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void user1ShouldBeAbleToDeleteSubmailbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
mailboxManager.createMailbox(inboxSubMailbox, session);
mailboxManager.deleteMailbox(inboxSubMailbox, session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isFalse();
}
@Test
protected void user1ShouldBeAbleToDeleteSubmailboxByid() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
MailboxPath inboxSubMailbox = new MailboxPath(inbox, "INBOX.Test");
MailboxId inboxSubMailboxId = mailboxManager.createMailbox(inboxSubMailbox, session).get();
mailboxManager.deleteMailbox(inboxSubMailboxId, session);
assertThat(mailboxManager.mailboxExists(inbox, session)).isTrue();
assertThat(mailboxManager.mailboxExists(inboxSubMailbox, session)).isFalse();
}
@Test
void listShouldReturnMailboxes() throws Exception {
session = mailboxManager.createSystemSession(Username.of("manager"));
mailboxManager.startProcessingRequest(session);
DataProvisioner.feedMailboxManager(mailboxManager);
assertThat(mailboxManager.list(session)).hasSize(DataProvisioner.EXPECTED_MAILBOXES_COUNT);
}
@Test
void listShouldReturnEmptyListWhenNoMailboxes() throws Exception {
session = mailboxManager.createSystemSession(Username.of("manager"));
assertThat(mailboxManager.list(session))
.isEmpty();
}
@Test
void user2ShouldBeAbleToCreateRootlessFolder() throws MailboxException {
session = mailboxManager.createSystemSession(USER_2);
MailboxPath trash = MailboxPath.forUser(USER_2, "Trash");
mailboxManager.createMailbox(trash, session);
assertThat(mailboxManager.mailboxExists(trash, session)).isTrue();
}
@Test
void user2ShouldBeAbleToCreateNestedFoldersWithoutTheirParents() throws Exception {
session = mailboxManager.createSystemSession(USER_2);
MailboxPath nestedFolder = MailboxPath.forUser(USER_2, "INBOX.testfolder");
mailboxManager.createMailbox(nestedFolder, session);
assertThat(mailboxManager.mailboxExists(nestedFolder, session)).isTrue();
mailboxManager.getMailbox(MailboxPath.inbox(session), session)
.appendMessage(AppendCommand.from(message), session);
}
@Test
void moveMessagesShouldNotThrowWhenMovingAllMessagesOfAnEmptyMailbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThatCode(() -> mailboxManager.moveMessages(MessageRange.all(), inbox, inbox, session))
.doesNotThrowAnyException();
}
@Test
void moveMessagesShouldMoveAllMessagesFromOneMailboxToAnOtherOfASameUser() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Move));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
MailboxId inboxId = mailboxManager.createMailbox(inbox, session).get();
MailboxPath otherMailbox = MailboxPath.forUser(USER_1, "otherMailbox");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailbox, session).get();
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox, session);
MessageId messageId1 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MessageId messageId2 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
mailboxManager.moveMessages(MessageRange.all(), inbox, otherMailbox, session);
MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(inboxId)
.build();
MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(inboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.isEmpty();
assertThat(mailboxManager.search(otherMailboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId1, messageId2);
}
@Test
void moveMessagesShouldMoveOnlyOneMessageFromOneMailboxToAnOtherOfASameUser() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.Move));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
MailboxId inboxId = mailboxManager.createMailbox(inbox, session).get();
MailboxPath otherMailbox = MailboxPath.forUser(USER_1, "otherMailbox");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailbox, session).get();
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox, session);
ComposedMessageId composedMessageId1 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session);
MessageId messageId2 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
mailboxManager.moveMessages(MessageRange.one(composedMessageId1.getUid()), inbox, otherMailbox, session);
MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(inboxId)
.build();
MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(inboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId2);
assertThat(mailboxManager.search(otherMailboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(composedMessageId1.getMessageId());
}
@Test
void moveMessagesShouldThrowWhenMovingMessageFromMailboxNotBelongingToSameUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(sessionUser1);
mailboxManager.createMailbox(inbox1, sessionUser1);
MailboxPath inbox2 = MailboxPath.inbox(sessionUser2);
mailboxManager.createMailbox(inbox2, sessionUser2);
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox1, sessionUser1);
inboxMessageManager
.appendMessage(AppendCommand.from(message), sessionUser1);
assertThatThrownBy(() -> mailboxManager.moveMessages(MessageRange.all(), inbox1, inbox2, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void moveMessagesShouldThrowWhenMovingMessageToMailboxNotBelongingToSameUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(sessionUser1);
mailboxManager.createMailbox(inbox1, sessionUser1);
MailboxPath inbox2 = MailboxPath.inbox(sessionUser2);
mailboxManager.createMailbox(inbox2, sessionUser2);
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox1, sessionUser1);
inboxMessageManager
.appendMessage(AppendCommand.from(message), sessionUser1);
assertThatThrownBy(() -> mailboxManager.moveMessages(MessageRange.all(), inbox1, inbox2, sessionUser1))
.isInstanceOf(MailboxException.class);
}
@Test
void copyMessagesShouldNotThrowWhenMovingAllMessagesOfAnEmptyMailbox() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session);
assertThatCode(() -> mailboxManager.copyMessages(MessageRange.all(), inbox, inbox, session))
.doesNotThrowAnyException();
}
@Test
void copyMessagesShouldCopyAllMessagesFromOneMailboxToAnOtherOfASameUser() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
MailboxId inboxId = mailboxManager.createMailbox(inbox, session).get();
MailboxPath otherMailbox = MailboxPath.forUser(USER_1, "otherMailbox");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailbox, session).get();
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox, session);
MessageId messageId1 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MessageId messageId2 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
mailboxManager.copyMessages(MessageRange.all(), inbox, otherMailbox, session);
MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(inboxId)
.build();
MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(inboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId1, messageId2);
assertThat(mailboxManager.search(otherMailboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId1, messageId2);
}
@Test
void copyMessagesShouldCopyOnlyOneMessageFromOneMailboxToAnOtherOfASameUser() throws Exception {
assumeTrue(mailboxManager.hasCapability(MailboxCapabilities.ACL));
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
MailboxId inboxId = mailboxManager.createMailbox(inbox, session).get();
MailboxPath otherMailbox = MailboxPath.forUser(USER_1, "otherMailbox");
MailboxId otherMailboxId = mailboxManager.createMailbox(otherMailbox, session).get();
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox, session);
ComposedMessageId composedMessageId1 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session);
MessageId messageId2 = inboxMessageManager
.appendMessage(AppendCommand.from(message), session)
.getMessageId();
MessageId messageId1 = composedMessageId1.getMessageId();
mailboxManager.copyMessages(MessageRange.one(composedMessageId1.getUid()), inbox, otherMailbox, session);
MultimailboxesSearchQuery inboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(inboxId)
.build();
MultimailboxesSearchQuery otherMailboxQuery = MultimailboxesSearchQuery
.from(new SearchQuery())
.inMailboxes(otherMailboxId)
.build();
assertThat(mailboxManager.search(inboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId1, messageId2);
assertThat(mailboxManager.search(otherMailboxQuery, session, DEFAULT_MAXIMUM_LIMIT))
.containsExactly(messageId1);
}
@Test
@Disabled("JAMES-2993 It seems that getMailbox by path in MailboxManager does not check that the mailbox belongs to user, "
+ "compared to getMailbox by id that actually does assert it")
void copyMessagesShouldThrowWhenCopyingMessageFromMailboxNotBelongingToSameUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(sessionUser1);
mailboxManager.createMailbox(inbox1, sessionUser1);
MailboxPath inbox2 = MailboxPath.inbox(sessionUser2);
mailboxManager.createMailbox(inbox2, sessionUser2);
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox1, sessionUser1);
inboxMessageManager
.appendMessage(AppendCommand.from(message), sessionUser1);
assertThatThrownBy(() -> mailboxManager.copyMessages(MessageRange.all(), inbox1, inbox2, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void copyMessagesShouldThrowWhenCopyingMessageToMailboxNotBelongingToSameUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath inbox1 = MailboxPath.inbox(sessionUser1);
mailboxManager.createMailbox(inbox1, sessionUser1);
MailboxPath inbox2 = MailboxPath.inbox(sessionUser2);
mailboxManager.createMailbox(inbox2, sessionUser2);
MessageManager inboxMessageManager = mailboxManager.getMailbox(inbox1, sessionUser1);
inboxMessageManager
.appendMessage(AppendCommand.from(message), sessionUser1);
assertThatThrownBy(() -> mailboxManager.copyMessages(MessageRange.all(), inbox1, inbox2, sessionUser1))
.isInstanceOf(MailboxException.class);
}
@Test
void createMailboxShouldNotThrowWhenMailboxPathBelongsToUser() throws MailboxException {
session = mailboxManager.createSystemSession(USER_1);
Optional<MailboxId> mailboxId = mailboxManager
.createMailbox(MailboxPath.forUser(USER_1, "mailboxName"), session);
assertThat(mailboxId).isNotEmpty();
}
@Test
void createMailboxShouldThrowWhenMailboxPathBelongsToAnotherUser() {
session = mailboxManager.createSystemSession(USER_1);
assertThatThrownBy(() -> mailboxManager
.createMailbox(MailboxPath.forUser(USER_2, "mailboxName"), session))
.isInstanceOf(MailboxException.class);
}
@Test
void getMailboxShouldThrowWhenMailboxDoesNotExist() {
session = mailboxManager.createSystemSession(USER_1);
assertThatThrownBy(() -> mailboxManager.getMailbox(MailboxPath.forUser(USER_1, "mailboxName"), session))
.isInstanceOf(MailboxException.class);
}
@Test
void getMailboxByPathShouldReturnMailboxWhenBelongingToUser() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "mailboxName");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
assertThat(mailboxManager.getMailbox(mailboxPath, session).getId())
.isEqualTo(mailboxId.get());
}
@Test
protected void getMailboxByIdShouldReturnMailboxWhenBelongingToUser() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "mailboxName");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, session);
assertThat(mailboxManager.getMailbox(mailboxId.get(), session).getId())
.isEqualTo(mailboxId.get());
}
@Test
@Disabled("JAMES-2993 It seems that getMailbox by path in MailboxManager does not check that the mailbox belongs to user, "
+ "compared to getMailbox by id that actually does assert it")
void getMailboxByPathShouldThrowWhenMailboxNotBelongingToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "mailboxName");
mailboxManager.createMailbox(mailboxPath, sessionUser1);
assertThatThrownBy(() -> mailboxManager.getMailbox(mailboxPath, sessionUser2))
.isInstanceOf(MailboxException.class);
}
@Test
void getMailboxByIdShouldThrowWhenMailboxNotBelongingToUser() throws Exception {
MailboxSession sessionUser1 = mailboxManager.createSystemSession(USER_1);
MailboxSession sessionUser2 = mailboxManager.createSystemSession(USER_2);
MailboxPath mailboxPath = MailboxPath.forUser(USER_1, "mailboxName");
Optional<MailboxId> mailboxId = mailboxManager.createMailbox(mailboxPath, sessionUser1);
assertThatThrownBy(() -> mailboxManager.getMailbox(mailboxId.get(), sessionUser2))
.isInstanceOf(MailboxException.class);
}
}
@Nested
class SessionTests {
@Test
void createUser1SystemSessionShouldReturnValidSession() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
assertThat(session.getUser()).isEqualTo(USER_1);
}
@Test
void closingSessionShouldWork() {
session = mailboxManager.createSystemSession(USER_1);
mailboxManager.startProcessingRequest(session);
mailboxManager.logout(session);
mailboxManager.endProcessingRequest(session);
assertThat(session.isOpen()).isFalse();
}
}
@Nested
class HookTests {
@Nested
class PreDeletion {
private MailboxPath inbox;
private MailboxId inboxId;
private MailboxId anotherMailboxId;
private MessageManager inboxManager;
private MessageManager anotherMailboxManager;
@BeforeEach
void setUp() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
inbox = MailboxPath.inbox(session);
MailboxPath anotherMailboxPath = MailboxPath.forUser(USER_1, "anotherMailbox");
anotherMailboxId = mailboxManager.createMailbox(anotherMailboxPath, session).get();
inboxId = mailboxManager.createMailbox(inbox, session).get();
inboxManager = mailboxManager.getMailbox(inbox, session);
anotherMailboxManager = mailboxManager.getMailbox(anotherMailboxPath, session);
}
@Test
void expungeShouldCallAllPreDeletionHooks() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
inboxManager.expunge(MessageRange.one(composeId.getUid()), session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(1)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(1)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getValue().getDeletionMetadataList())
.hasSize(1)
.hasSameElementsAs(preDeleteCaptor2.getValue().getDeletionMetadataList())
.allSatisfy(deleteMetadata -> SoftAssertions.assertSoftly(softy -> {
softy.assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId);
softy.assertThat(deleteMetadata.getMessageMetaData().getMessageId()).isEqualTo(composeId.getMessageId());
}));
}
@Test
void deleteMailboxShouldCallAllPreDeletionHooks() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
mailboxManager.deleteMailbox(inbox, session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(1)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(1)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getValue().getDeletionMetadataList())
.hasSize(1)
.hasSameElementsAs(preDeleteCaptor2.getValue().getDeletionMetadataList())
.allSatisfy(deleteMetadata -> SoftAssertions.assertSoftly(softy -> {
softy.assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId);
softy.assertThat(deleteMetadata.getMessageMetaData().getMessageId()).isEqualTo(composeId.getMessageId());
}));
}
@Test
void deleteMailboxByIdShouldCallAllPreDeletionHooks() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
mailboxManager.deleteMailbox(inboxId, session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(1)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(1)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getValue().getDeletionMetadataList())
.hasSize(1)
.hasSameElementsAs(preDeleteCaptor2.getValue().getDeletionMetadataList())
.allSatisfy(deleteMetadata -> SoftAssertions.assertSoftly(softy -> {
softy.assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId);
softy.assertThat(deleteMetadata.getMessageMetaData().getMessageId()).isEqualTo(composeId.getMessageId());
}));
}
@Test
void expungeShouldCallAllPreDeletionHooksOnEachMessageDeletionCall() throws Exception {
ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
ComposedMessageId composeId2 = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
inboxManager.expunge(MessageRange.one(composeId1.getUid()), session);
inboxManager.expunge(MessageRange.one(composeId2.getUid()), session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(2)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(2)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getAllValues())
.hasSize(2)
.hasSameElementsAs(preDeleteCaptor2.getAllValues())
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
.allSatisfy(deleteMetadata -> assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId))
.extracting(deleteMetadata -> deleteMetadata.getMessageMetaData().getMessageId())
.containsOnly(composeId1.getMessageId(), composeId2.getMessageId());
}
@Test
void expungeShouldCallAllPreDeletionHooksOnlyOnMessagesMarkedAsDeleted() throws Exception {
ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
inboxManager.appendMessage(AppendCommand.builder()
.build(message), session);
inboxManager.expunge(MessageRange.all(), session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(1)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(1)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getValue().getDeletionMetadataList())
.hasSize(1)
.hasSameElementsAs(preDeleteCaptor2.getValue().getDeletionMetadataList())
.allSatisfy(deleteMetadata -> SoftAssertions.assertSoftly(softy -> {
softy.assertThat(deleteMetadata.getMailboxId()).isEqualTo(inboxId);
softy.assertThat(deleteMetadata.getMessageMetaData().getMessageId()).isEqualTo(composeId1.getMessageId());
}));
}
@Test
void expungeShouldNotCallPredeletionHooksWhenNoMessagesMarkedAsDeleted() throws Exception {
inboxManager.appendMessage(AppendCommand.builder()
.build(message), session);
inboxManager.expunge(MessageRange.all(), session);
verifyZeroInteractions(preDeletionHook1);
verifyZeroInteractions(preDeletionHook2);
}
@Test
void expungeShouldCallAllPreDeletionHooksOnEachMessageDeletionOnDifferentMailboxes() throws Exception {
ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
ComposedMessageId composeId2 = anotherMailboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
inboxManager.expunge(MessageRange.one(composeId1.getUid()), session);
anotherMailboxManager.expunge(MessageRange.one(composeId2.getUid()), session);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor1 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
ArgumentCaptor<PreDeletionHook.DeleteOperation> preDeleteCaptor2 = ArgumentCaptor.forClass(PreDeletionHook.DeleteOperation.class);
verify(preDeletionHook1, times(2)).notifyDelete(preDeleteCaptor1.capture());
verify(preDeletionHook2, times(2)).notifyDelete(preDeleteCaptor2.capture());
assertThat(preDeleteCaptor1.getAllValues())
.hasSameElementsAs(preDeleteCaptor2.getAllValues())
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
.extracting(deleteMetadata -> deleteMetadata.getMessageMetaData().getMessageId())
.containsOnly(composeId1.getMessageId(), composeId2.getMessageId());
assertThat(preDeleteCaptor1.getAllValues())
.hasSameElementsAs(preDeleteCaptor2.getAllValues())
.flatExtracting(PreDeletionHook.DeleteOperation::getDeletionMetadataList)
.extracting(MetadataWithMailboxId::getMailboxId)
.containsOnly(inboxId, anotherMailboxId);
}
@Test
void expungeShouldNotBeExecutedWhenOneOfPreDeleteHooksFails() throws Exception {
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
.thenThrow(new RuntimeException("throw at hook 1"));
ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
assertThatThrownBy(() -> inboxManager.expunge(MessageRange.one(composeId1.getUid()), session))
.isInstanceOf(RuntimeException.class);
assertThat(ImmutableList.copyOf(inboxManager.getMessages(MessageRange.one(composeId1.getUid()), FetchGroup.MINIMAL, session))
.stream()
.map(MessageResult::getMessageId))
.hasSize(1)
.containsOnly(composeId1.getMessageId());
}
@Test
void expungeShouldBeExecutedAfterAllHooksFinish() throws Exception {
CountDownLatch latchForHook1 = new CountDownLatch(1);
when(preDeletionHook1.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
.thenAnswer(invocation -> {
latchForHook1.countDown();
return Mono.empty();
});
CountDownLatch latchForHook2 = new CountDownLatch(1);
when(preDeletionHook2.notifyDelete(any(PreDeletionHook.DeleteOperation.class)))
.thenAnswer(invocation -> {
latchForHook2.countDown();
return Mono.empty();
});
ComposedMessageId composeId1 = inboxManager.appendMessage(AppendCommand.builder().build(message), session);
inboxManager.setFlags(new Flags(Flags.Flag.DELETED), MessageManager.FlagsUpdateMode.ADD,
MessageRange.one(composeId1.getUid()), session);
inboxManager.expunge(MessageRange.all(), session);
latchForHook1.await();
latchForHook2.await();
assertThat(inboxManager.getMessages(MessageRange.one(composeId1.getUid()), FetchGroup.MINIMAL, session))
.toIterable()
.isEmpty();
}
}
}
@Nested
class MessageTests {
private MessageManager inboxManager;
@BeforeEach
void setUp() throws Exception {
session = mailboxManager.createSystemSession(USER_1);
MailboxPath inbox = MailboxPath.inbox(session);
mailboxManager.createMailbox(inbox, session).get();
inboxManager = mailboxManager.getMailbox(inbox, session);
}
@Test
void getMessagesShouldIncludeHasAttachmentInformation() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(ClassLoaderUtils.getSystemResourceAsSharedStream("eml/twoAttachmentsApi.eml")), session);
MessageResultIterator messages = inboxManager.getMessages(MessageRange.one(composeId.getUid()), FetchGroup.MINIMAL, session);
assertThat(messages).toIterable()
.hasSize(1)
.first()
.satisfies(Throwing.consumer(messageResult -> assertThat(messageResult.hasAttachments()).isTrue()));
}
@Test
void getMessagesShouldNotIncludeAttachmentInformationWhenNone() throws Exception {
ComposedMessageId composeId = inboxManager.appendMessage(AppendCommand.builder()
.withFlags(new Flags(Flags.Flag.DELETED))
.build(message), session);
MessageResultIterator messages = inboxManager.getMessages(MessageRange.one(composeId.getUid()), FetchGroup.MINIMAL, session);
assertThat(messages).toIterable()
.hasSize(1)
.first()
.satisfies(Throwing.consumer(messageResult -> assertThat(messageResult.hasAttachments()).isFalse()));
}
}
}