This is an automated email from the ASF dual-hosted git repository. btellier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 286bbb181dc105d55e8e10986e3352a91dea6916 Author: Benoit Tellier <[email protected]> AuthorDate: Fri Apr 7 12:33:33 2023 +0700 JAMES-3899 WithStorageDirective: Support flag storage directives - Seen - Flagged - Keyword --- .../WithStorageDirectiveIntegrationTest.java | 62 ++++++++++++++ .../james/transport/mailets/ToSenderFolder.java | 6 +- .../transport/mailets/WithStorageDirective.java | 70 +++++++++++++--- .../transport/mailets/delivery/MailStore.java | 3 + .../mailets/delivery/MailboxAppender.java | 5 +- .../mailets/delivery/MailboxAppenderImpl.java | 27 +++--- .../mailets/delivery/SimpleMailStore.java | 60 ++++++++++++- .../mailets/WithStorageDirectiveTest.java | 97 ++++++++++++++++++++++ .../mailets/delivery/MailboxAppenderImplTest.java | 25 ++++-- .../mailets/delivery/SimpleMailStoreTest.java | 8 +- 10 files changed, 325 insertions(+), 38 deletions(-) diff --git a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java index bf33b13891..506162e41f 100644 --- a/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java +++ b/server/mailet/integration-testing/src/test/java/org/apache/james/mailets/WithStorageDirectiveIntegrationTest.java @@ -25,6 +25,7 @@ import static org.apache.james.mailets.configuration.Constants.LOCALHOST_IP; import static org.apache.james.mailets.configuration.Constants.PASSWORD; import static org.apache.james.mailets.configuration.Constants.RECIPIENT; import static org.apache.james.mailets.configuration.Constants.awaitAtMostOneMinute; +import static org.assertj.core.api.Assertions.assertThat; import java.io.File; @@ -76,6 +77,67 @@ class WithStorageDirectiveIntegrationTest { .awaitMessage(awaitAtMostOneMinute); } + @Test + void seenShouldWork(@TempDir File temporaryFolder) throws Exception { + setUp(temporaryFolder, MailetConfiguration.builder() + .matcher(SenderIsLocal.class) + .mailet(WithStorageDirective.class) + .addProperty("seen", "true")); + + testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort()) + .login(RECIPIENT, PASSWORD); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(FROM, PASSWORD) + .sendMessage(FROM, RECIPIENT); + + testIMAPClient.select("INBOX") + .awaitMessage(awaitAtMostOneMinute); + + assertThat(testIMAPClient.hasAMessageWithFlags("\\Seen")).isTrue(); + } + + @Test + void importantShouldWork(@TempDir File temporaryFolder) throws Exception { + setUp(temporaryFolder, MailetConfiguration.builder() + .matcher(SenderIsLocal.class) + .mailet(WithStorageDirective.class) + .addProperty("important", "true")); + + testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort()) + .login(RECIPIENT, PASSWORD); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(FROM, PASSWORD) + .sendMessage(FROM, RECIPIENT); + + testIMAPClient.select("INBOX") + .awaitMessage(awaitAtMostOneMinute); + + assertThat(testIMAPClient.hasAMessageWithFlags("\\Flagged")).isTrue(); + } + + @Test + void keywordsShouldWork(@TempDir File temporaryFolder) throws Exception { + setUp(temporaryFolder, MailetConfiguration.builder() + .matcher(SenderIsLocal.class) + .mailet(WithStorageDirective.class) + .addProperty("keywords", "abc,def")); + + testIMAPClient.connect(LOCALHOST_IP, jamesServer.getProbe(ImapGuiceProbe.class).getImapPort()) + .login(RECIPIENT, PASSWORD); + + messageSender.connect(LOCALHOST_IP, jamesServer.getProbe(SmtpGuiceProbe.class).getSmtpPort()) + .authenticate(FROM, PASSWORD) + .sendMessage(FROM, RECIPIENT); + + testIMAPClient.select("INBOX") + .awaitMessage(awaitAtMostOneMinute); + + assertThat(testIMAPClient.hasAMessageWithFlags("abc")).isTrue(); + assertThat(testIMAPClient.hasAMessageWithFlags("def")).isTrue(); + } + private void setUp(File temporaryFolder, MailetConfiguration.Builder mailet) throws Exception { jamesServer = TemporaryJamesServer.builder() .withMailetContainer(TemporaryJamesServer.defaultMailetContainerConfiguration() diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java index 311ba38768..d808b81874 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/ToSenderFolder.java @@ -18,8 +18,11 @@ ****************************************************************/ package org.apache.james.transport.mailets; +import java.util.Optional; + import javax.inject.Inject; import javax.inject.Named; +import javax.mail.Flags; import javax.mail.MessagingException; import org.apache.james.core.MailAddress; @@ -53,6 +56,7 @@ import org.slf4j.LoggerFactory; @Experimental public class ToSenderFolder extends GenericMailet { private static final Logger LOGGER = LoggerFactory.getLogger(ToSenderFolder.class); + private static final Optional<Flags> NO_FLAGS = Optional.empty(); private final UsersRepository usersRepository; private final MailboxManager mailboxManager; @@ -84,7 +88,7 @@ public class ToSenderFolder extends GenericMailet { MailAddress sender = mail.getMaybeSender().get(); Username username = retrieveUser(sender); - mailboxAppender.append(mail.getMessage(), username, folder).block(); + mailboxAppender.append(mail.getMessage(), username, folder, NO_FLAGS).block(); LOGGER.error("Local delivery with ToSenderFolder mailet for mail {} with sender {} in folder {}", mail.getName(), sender, folder); } diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java index 178b51aeae..857f69b48e 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/WithStorageDirective.java @@ -19,10 +19,14 @@ package org.apache.james.transport.mailets; +import java.util.Collection; +import java.util.Optional; + import javax.inject.Inject; import javax.mail.MessagingException; import org.apache.james.core.MailAddress; +import org.apache.james.core.Username; import org.apache.james.transport.mailets.delivery.MailStore; import org.apache.james.user.api.UsersRepository; import org.apache.mailet.Attribute; @@ -33,7 +37,9 @@ import org.apache.mailet.base.GenericMailet; import com.github.fge.lambdas.consumers.ThrowingConsumer; import com.google.common.base.Preconditions; -import com.google.common.base.Strings; +import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableSet; +import com.google.common.primitives.Booleans; /** * WithStorageDirective position storage directive for the recipients of this email. @@ -41,21 +47,37 @@ import com.google.common.base.Strings; * These directives are used by <strong>LocalDelivery</strong> mailet when adding the email to the recipients mailboxes. * * The following storage directives can be set: - * - targetFolderName: the folder to append the email in. (compulsory) + * - targetFolderName: the folder to append the email in. Defaults to none (INBOX). + * - seen: boolean, whether the message should be automatically marked as seen. Defaults to false. + * - important: boolean, whether the message should be automatically marked as important. Defaults to false. + * - keywords: set of string, encoded as a string (value are coma separated). IMAP user flags to set for the message. Defaults to none. + * + * At least one of the storage directives should be set. * * Example: * * <mailet match="IsMarkedAsSpam" class="WithStorageDirective"> * <targetFolderName>Spam</targetFolderName> + * <seen>true</seen> + * <important>true</important> + * <keywords>keyword1,keyword2</targetFolderName> * </mailet> */ public class WithStorageDirective extends GenericMailet { - - public static final String TARGET_FOLDER_NAME = "targetFolderName"; + static final String TARGET_FOLDER_NAME = "targetFolderName"; + static final String SEEN = "seen"; + static final String IMPORTANT = "important"; + static final String KEYWORDS = "keywords"; + private static final Splitter KEYWORD_SPLITTER = Splitter.on(',') + .omitEmptyStrings() + .trimResults(); private final UsersRepository usersRepository; - private AttributeValue<String> targetFolderName; + private Optional<AttributeValue<String>> targetFolderName; + private Optional<AttributeValue<Boolean>> seen; + private Optional<AttributeValue<Boolean>> important; + private Optional<AttributeValue<Collection<AttributeValue<?>>>> keywords; @Inject public WithStorageDirective(UsersRepository usersRepository) { @@ -64,13 +86,33 @@ public class WithStorageDirective extends GenericMailet { @Override public void init() throws MessagingException { - targetFolderName = AttributeValue.of(validateMailetConfiguration(TARGET_FOLDER_NAME)); + Preconditions.checkState( + Booleans.countTrue( + getInitParameterAsOptional(TARGET_FOLDER_NAME).isPresent(), + getInitParameterAsOptional(SEEN).isPresent(), + getInitParameterAsOptional(IMPORTANT).isPresent(), + getInitParameterAsOptional(KEYWORDS).isPresent()) > 0, + "Expecting one of the storage directives to be specified: [%s, %s, %s, %s]", + TARGET_FOLDER_NAME, SEEN, IMPORTANT, KEYWORDS); + Preconditions.checkState(validBooleanParameter(getInitParameterAsOptional(SEEN)), "'%s' needs to be a boolean", SEEN); + Preconditions.checkState(validBooleanParameter(getInitParameterAsOptional(IMPORTANT)), "'%s' needs to be a boolean", IMPORTANT); + + targetFolderName = getInitParameterAsOptional(TARGET_FOLDER_NAME).map(AttributeValue::of); + seen = getInitParameterAsOptional(SEEN).map(Boolean::parseBoolean).map(AttributeValue::of); + important = getInitParameterAsOptional(IMPORTANT).map(Boolean::parseBoolean).map(AttributeValue::of); + keywords = getInitParameterAsOptional(KEYWORDS).map(this::parseKeywords).map(AttributeValue::of); } - private String validateMailetConfiguration(String initParameterName) { - String initParameterValue = getInitParameter(initParameterName); - Preconditions.checkState(!Strings.isNullOrEmpty(initParameterValue), "You need to specify %s", initParameterName); - return initParameterValue; + private Collection<AttributeValue<?>> parseKeywords(String s) { + return KEYWORD_SPLITTER + .splitToStream(s) + .map(AttributeValue::of) + .collect(ImmutableSet.toImmutableSet()); + } + + private boolean validBooleanParameter(Optional<String> parameter) { + return parameter.map(v -> v.equals("true") || v.equals("false")) + .orElse(true); } @Override @@ -81,9 +123,11 @@ public class WithStorageDirective extends GenericMailet { public ThrowingConsumer<MailAddress> addStorageDirective(Mail mail) { return recipient -> { - AttributeName attributeNameForUser = AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + usersRepository.getUsername(recipient).asString()); - mail.setAttribute(new Attribute(attributeNameForUser, targetFolderName)); + Username username = usersRepository.getUsername(recipient); + targetFolderName.ifPresent(value -> mail.setAttribute(new Attribute(AttributeName.of(MailStore.DELIVERY_PATH_PREFIX + username.asString()), value))); + seen.ifPresent(value -> mail.setAttribute(new Attribute(AttributeName.of(MailStore.SEEN_PREFIX + username.asString()), value))); + important.ifPresent(value -> mail.setAttribute(new Attribute(AttributeName.of(MailStore.IMPORTANT_PREFIX + username.asString()), value))); + keywords.ifPresent(value -> mail.setAttribute(new Attribute(AttributeName.of(MailStore.KEYWORDS_PREFIX + username.asString()), value))); }; - } } diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java index 598f934658..22241067e9 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailStore.java @@ -25,6 +25,9 @@ import org.reactivestreams.Publisher; public interface MailStore { String DELIVERY_PATH_PREFIX = "DeliveryPath_"; + String SEEN_PREFIX = "Seen_"; + String IMPORTANT_PREFIX = "Important_"; + String KEYWORDS_PREFIX = "Keywords_"; Publisher<Void> storeMail(MailAddress recipient, Mail mail); } diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java index 097b073d3e..0303f20976 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppender.java @@ -19,6 +19,9 @@ package org.apache.james.transport.mailets.delivery; +import java.util.Optional; + +import javax.mail.Flags; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; @@ -27,5 +30,5 @@ import org.apache.james.mailbox.model.ComposedMessageId; import org.reactivestreams.Publisher; public interface MailboxAppender { - Publisher<ComposedMessageId> append(MimeMessage mail, Username user, String folder) throws MessagingException; + Publisher<ComposedMessageId> append(MimeMessage mail, Username user, String folder, Optional<Flags> flags) throws MessagingException; } diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java index 76e500fd6e..ab59df51a1 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImpl.java @@ -21,7 +21,9 @@ package org.apache.james.transport.mailets.delivery; import java.io.IOException; import java.io.InputStream; +import java.util.Optional; +import javax.mail.Flags; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; @@ -54,9 +56,9 @@ public class MailboxAppenderImpl implements MailboxAppender { this.mailboxManager = mailboxManager; } - public Mono<ComposedMessageId> append(MimeMessage mail, Username user, String folder) throws MessagingException { + public Mono<ComposedMessageId> append(MimeMessage mail, Username user, String folder, Optional<Flags> flags) throws MessagingException { MailboxSession session = createMailboxSession(user); - return append(mail, user, useSlashAsSeparator(folder, session), session) + return append(mail, user, useSlashAsSeparator(folder, session), flags, session) .map(AppendResult::getId); } @@ -71,26 +73,29 @@ public class MailboxAppenderImpl implements MailboxAppender { return destination; } - private Mono<AppendResult> append(MimeMessage mail, Username user, String folder, MailboxSession mailboxSession) { + private Mono<AppendResult> append(MimeMessage mail, Username user, String folder, Optional<Flags> flags, MailboxSession mailboxSession) { MailboxPath mailboxPath = MailboxPath.forUser(user, folder); return Mono.using( () -> { mailboxManager.startProcessingRequest(mailboxSession); return mailboxSession; }, - session -> appendMessageToMailbox(mail, session, mailboxPath), + session -> appendMessageToMailbox(mail, session, mailboxPath, flags), this::closeProcessing) .onErrorMap(MailboxException.class, e -> new MessagingException("Unable to access mailbox.", e)); } - protected Mono<AppendResult> appendMessageToMailbox(MimeMessage mail, MailboxSession session, MailboxPath path) { + protected Mono<AppendResult> appendMessageToMailbox(MimeMessage mail, MailboxSession session, MailboxPath path, Optional<Flags> flags) { return createMailboxIfNotExist(session, path) - .flatMap(mailbox -> Mono.from(mailbox.appendMessageReactive( - MessageManager.AppendCommand.builder() - .recent() - .delivery() - .build(extractContent(mail)), - session))); + .flatMap(mailbox -> Mono.from(mailbox.appendMessageReactive(appendCommand(flags).build(extractContent(mail)), session))); + } + + private MessageManager.AppendCommand.Builder appendCommand(Optional<Flags> flags) { + MessageManager.AppendCommand.Builder builder = MessageManager.AppendCommand.builder() + .recent() + .delivery(); + return flags.map(builder::withFlags) + .orElse(builder); } private Content extractContent(MimeMessage mail) { diff --git a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java index 96edbbeb4a..44d2de771b 100644 --- a/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java +++ b/server/mailet/mailets/src/main/java/org/apache/james/transport/mailets/delivery/SimpleMailStore.java @@ -19,6 +19,11 @@ package org.apache.james.transport.mailets.delivery; +import java.util.Collection; +import java.util.Optional; +import java.util.stream.Stream; + +import javax.mail.Flags; import javax.mail.MessagingException; import org.apache.james.core.MailAddress; @@ -26,8 +31,10 @@ import org.apache.james.core.Username; import org.apache.james.metrics.api.Metric; import org.apache.james.user.api.UsersRepository; import org.apache.james.user.api.UsersRepositoryException; +import org.apache.mailet.Attribute; import org.apache.mailet.AttributeName; import org.apache.mailet.AttributeUtils; +import org.apache.mailet.AttributeValue; import org.apache.mailet.Mail; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,7 +104,9 @@ public class SimpleMailStore implements MailStore { String locatedFolder = locateFolder(username, mail); try { - return Mono.from(mailboxAppender.append(mail.getMessage(), username, locatedFolder)) + return Mono.from(mailboxAppender.append(mail.getMessage(), username, + locateFolder(username, mail), + extractFlags(username, mail))) .doOnSuccess(ids -> { metric.increment(); LOGGER.info("Local delivered mail {} with messageId {} successfully from {} to {} in folder {} with composedMessageId {}", @@ -108,7 +117,54 @@ public class SimpleMailStore implements MailStore { throw new RuntimeException("Could not retrieve mail message content", e); } } - + + private Optional<Flags> extractFlags(Username username, Mail mail) { + Optional<Attribute> seen = mail.getAttribute(AttributeName.of(MailStore.SEEN_PREFIX + username.asString())); + Optional<Attribute> important = mail.getAttribute(AttributeName.of(MailStore.IMPORTANT_PREFIX + username.asString())); + Optional<Attribute> keywords = mail.getAttribute(AttributeName.of(MailStore.KEYWORDS_PREFIX + username.asString())); + + if (seen.isEmpty() && important.isEmpty() && keywords.isEmpty()) { + return Optional.empty(); + } + + Flags flags = new Flags(); + flags.add(encodeFlag(seen, Flags.Flag.SEEN)); + flags.add(encodeFlag(important, Flags.Flag.FLAGGED)); + extractKeywords(keywords).forEach(flags::add); + + return Optional.of(flags); + } + + @SuppressWarnings("unchecked") + private Stream<String> extractKeywords(Optional<Attribute> keywords) { + return keywords + .map(Attribute::getValue) + .map(AttributeValue::getValue) + .filter(Collection.class::isInstance) + .map(Collection.class::cast) + .stream() + .flatMap(Collection::stream) + .filter(AttributeValue.class::isInstance) + .map(AttributeValue.class::cast) + .map(a -> ((AttributeValue<?>) a).getValue()) + .filter(String.class::isInstance) + .map(String.class::cast); + } + + private Flags encodeFlag(Optional<Attribute> attr, Flags.Flag flag) { + Flags flags = new Flags(); + attr.map(Attribute::getValue) + .map(AttributeValue::getValue) + .filter(Boolean.class::isInstance) + .map(Boolean.class::cast) + .ifPresent(seenFlag -> { + if (seenFlag) { + flags.add(flag); + } + }); + return flags; + } + private String getMessageId(Mail mail) { try { return mail.getMessage().getMessageID(); diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java index 5338cb8cc0..6ba7bf81c7 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/WithStorageDirectiveTest.java @@ -33,6 +33,7 @@ import org.apache.mailet.base.test.FakeMailetConfig; import org.assertj.core.api.SoftAssertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.testcontainers.shaded.com.google.common.collect.ImmutableSet; class WithStorageDirectiveTest { private static final DomainList NO_DOMAIN_LIST = null; @@ -81,6 +82,102 @@ class WithStorageDirectiveTest { new Attribute(recipient2, AttributeValue.of(targetFolderName))); } + @Test + void shouldSupportSeen() throws Exception { + testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.SEEN, "true") + .build()); + + FakeMail mail = FakeMail.builder() + .name("name") + .recipients(MailAddressFixture.RECIPIENT1) + .build(); + + testee.service(mail); + + AttributeName recipient1 = AttributeName.of("Seen_recipient1@localhost"); + assertThat(mail.attributes()) + .containsOnly( + new Attribute(recipient1, AttributeValue.of(true))); + } + + @Test + void shouldSupportImportant() throws Exception { + testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.IMPORTANT, "true") + .build()); + + FakeMail mail = FakeMail.builder() + .name("name") + .recipients(MailAddressFixture.RECIPIENT1) + .build(); + + testee.service(mail); + + AttributeName recipient1 = AttributeName.of("Important_recipient1@localhost"); + assertThat(mail.attributes()) + .containsOnly( + new Attribute(recipient1, AttributeValue.of(true))); + } + + @Test + void shouldSupportKeywords() throws Exception { + testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.KEYWORDS, "abc,def") + .build()); + + FakeMail mail = FakeMail.builder() + .name("name") + .recipients(MailAddressFixture.RECIPIENT1) + .build(); + + testee.service(mail); + + AttributeName recipient1 = AttributeName.of("Keywords_recipient1@localhost"); + assertThat(mail.attributes()) + .containsOnly( + new Attribute(recipient1, AttributeValue.of(ImmutableSet.of( + AttributeValue.of("abc"), + AttributeValue.of("def"))))); + } + + @Test + void shouldSanitizeKeywords() throws Exception { + testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.KEYWORDS, "abc, def,,") + .build()); + + FakeMail mail = FakeMail.builder() + .name("name") + .recipients(MailAddressFixture.RECIPIENT1) + .build(); + + testee.service(mail); + + AttributeName recipient1 = AttributeName.of("Keywords_recipient1@localhost"); + assertThat(mail.attributes()) + .containsOnly( + new Attribute(recipient1, AttributeValue.of(ImmutableSet.of( + AttributeValue.of("abc"), + AttributeValue.of("def"))))); + } + + @Test + void shouldRejectBadSeenValue() { + assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.SEEN, "bad") + .build())) + .isInstanceOf(IllegalStateException.class); + } + + @Test + void shouldRejectBadImportantValue() { + assertThatThrownBy(() -> testee.init(FakeMailetConfig.builder() + .setProperty(WithStorageDirective.IMPORTANT, "bad") + .build())) + .isInstanceOf(IllegalStateException.class); + } + @Test void serviceShouldNotThrowWhenNoRecipients() throws Exception { String targetFolderName = "Spam"; diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java index e50ffa49d6..e9a007975e 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/MailboxAppenderImplTest.java @@ -23,7 +23,9 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.time.Duration; +import java.util.Optional; +import javax.mail.Flags; import javax.mail.MessagingException; import javax.mail.internet.MimeMessage; @@ -48,6 +50,7 @@ class MailboxAppenderImplTest { public static final Username USER = Username.of("user"); public static final String FOLDER = "folder"; public static final String EMPTY_FOLDER = ""; + private static final Optional<Flags> NO_FLAGS = Optional.empty(); private MailboxAppenderImpl testee; private MailboxManager mailboxManager; @@ -70,7 +73,7 @@ class MailboxAppenderImplTest { @Test void appendShouldAddMessageToDesiredMailbox() throws Exception { - Mono.from(testee.append(mimeMessage, USER, FOLDER)).block(); + Mono.from(testee.append(mimeMessage, USER, FOLDER, NO_FLAGS)).block(); MessageResultIterator messages = mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session) .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session); @@ -84,7 +87,7 @@ class MailboxAppenderImplTest { MailboxPath mailboxPath = MailboxPath.forUser(USER, FOLDER); mailboxManager.createMailbox(mailboxPath, session); - Mono.from(testee.append(mimeMessage, USER, FOLDER)).block(); + Mono.from(testee.append(mimeMessage, USER, FOLDER, NO_FLAGS)).block(); MessageResultIterator messages = mailboxManager.getMailbox(mailboxPath, session) .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session); @@ -95,13 +98,13 @@ class MailboxAppenderImplTest { @Test void appendShouldNotAppendToEmptyFolder() { - assertThatThrownBy(() -> Mono.from(testee.append(mimeMessage, USER, EMPTY_FOLDER)).block()) + assertThatThrownBy(() -> Mono.from(testee.append(mimeMessage, USER, EMPTY_FOLDER, NO_FLAGS)).block()) .isInstanceOf(MessagingException.class); } @Test void appendShouldRemovePathSeparatorAsFirstChar() throws Exception { - Mono.from(testee.append(mimeMessage, USER, "." + FOLDER)).block(); + Mono.from(testee.append(mimeMessage, USER, "." + FOLDER, NO_FLAGS)).block(); MessageResultIterator messages = mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session) .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session); @@ -110,9 +113,19 @@ class MailboxAppenderImplTest { .hasSize(1); } + @Test + void appendShouldSupportFlags() throws Exception { + Mono.from(testee.append(mimeMessage, USER, "." + FOLDER, Optional.of(new Flags(Flags.Flag.SEEN)))).block(); + + MessageResultIterator messages = mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER), session) + .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session); + + assertThat(messages.next().getFlags().contains(Flags.Flag.SEEN)).isTrue(); + } + @Test void appendShouldReplaceSlashBySeparator() throws Exception { - Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any")).block(); + Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any", NO_FLAGS)).block(); MessageResultIterator messages = mailboxManager.getMailbox(MailboxPath.forUser(USER, FOLDER + ".any"), session) .getMessages(MessageRange.all(), FetchGroup.FULL_CONTENT, session); @@ -124,7 +137,7 @@ class MailboxAppenderImplTest { @RepeatedTest(20) void appendShouldNotFailInConcurrentEnvironment() throws Exception { ConcurrentTestRunner.builder() - .reactorOperation((a, b) -> Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any")).then()) + .reactorOperation((a, b) -> Mono.from(testee.append(mimeMessage, USER, FOLDER + "/any", NO_FLAGS)).then()) .threadCount(100) .runSuccessfullyWithin(Duration.ofMinutes(1)); } diff --git a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java index d57e070e59..fabb57a14f 100644 --- a/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java +++ b/server/mailet/mailets/src/test/java/org/apache/james/transport/mailets/delivery/SimpleMailStoreTest.java @@ -50,7 +50,7 @@ class SimpleMailStoreTest { @BeforeEach void setUp() throws Exception { mailboxAppender = mock(MailboxAppenderImpl.class); - when(mailboxAppender.append(any(), any(), any())).thenReturn(Mono.empty()); + when(mailboxAppender.append(any(), any(), any(), any())).thenReturn(Mono.empty()); usersRepository = mock(UsersRepository.class); testee = SimpleMailStore.builder() .usersRepository(usersRepository) @@ -76,7 +76,7 @@ class SimpleMailStoreTest { .build(); testee.storeMail(recipient, mail); - verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.asString())), eq(FOLDER)); + verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.asString())), eq(FOLDER), any()); } @Test @@ -89,7 +89,7 @@ class SimpleMailStoreTest { .build(); testee.storeMail(recipient, mail); - verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.getLocalPart())), eq(FOLDER)); + verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.getLocalPart())), eq(FOLDER), any()); } @Test @@ -102,6 +102,6 @@ class SimpleMailStoreTest { .build(); testee.storeMail(recipient, mail); - verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.toString())), eq(FOLDER)); + verify(mailboxAppender).append(any(MimeMessage.class), eq(Username.of(recipient.toString())), eq(FOLDER), any()); } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
