You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2019/03/01 02:48:16 UTC
[james-project] 08/08: MAILBOX-381 DeletedMessage <-> Mail
conversion
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 945b91e3d891174dabac262104371a44e6114e1b
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Mon Feb 25 16:29:11 2019 +0700
MAILBOX-381 DeletedMessage <-> Mail conversion
---
.../java/org/apache/mailet/AttributeValue.java | 4 +-
.../java/org/apache/james/vault/MailConverter.java | 159 ++++++++++++++
.../org/apache/james/vault/SerializableDate.java | 63 ++++++
.../org/apache/james/vault/SerializableUser.java | 62 ++++++
.../org/apache/james/vault/MailConverterTest.java | 237 +++++++++++++++++++++
.../apache/james/vault/SerializableDateTest.java | 52 +++++
.../apache/james/vault/SerializableUserTest.java | 52 +++++
7 files changed, 626 insertions(+), 3 deletions(-)
diff --git a/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java b/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
index 79c097a..dd496f6 100644
--- a/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
+++ b/mailet/api/src/main/java/org/apache/mailet/AttributeValue.java
@@ -35,7 +35,6 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.base.Preconditions;
@@ -174,8 +173,7 @@ public class AttributeValue<T> {
}
}
- @VisibleForTesting
- static AttributeValue<?> fromJson(JsonNode input) {
+ public static AttributeValue<?> fromJson(JsonNode input) {
return Optional.ofNullable(input)
.filter(ObjectNode.class::isInstance)
.map(ObjectNode.class::cast)
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/MailConverter.java b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/MailConverter.java
new file mode 100644
index 0000000..1f1a68b
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/MailConverter.java
@@ -0,0 +1,159 @@
+/****************************************************************
+ * 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.vault;
+
+import java.io.InputStream;
+import java.time.ZonedDateTime;
+import java.util.List;
+import java.util.Optional;
+import java.util.Properties;
+
+import javax.mail.MessagingException;
+import javax.mail.Session;
+import javax.mail.internet.MimeMessage;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MessageId;
+import org.apache.james.server.core.MailImpl;
+import org.apache.mailet.AttributeName;
+import org.apache.mailet.AttributeUtils;
+import org.apache.mailet.AttributeValue;
+import org.apache.mailet.Mail;
+
+import com.github.steveash.guavate.Guavate;
+import com.google.common.collect.ImmutableList;
+
+class MailConverter {
+ static final AttributeName ORIGIN_MAILBOXES_ATTRIBUTE_NAME = AttributeName.of("originMailboxes");
+ static final AttributeName HAS_ATTACHMENT_ATTRIBUTE_NAME = AttributeName.of("hasAttachment");
+ static final AttributeName OWNER_ATTRIBUTE_NAME = AttributeName.of("owner");
+ static final AttributeName DELIVERY_DATE_ATTRIBUTE_NAME = AttributeName.of("deliveryDate");
+ static final AttributeName DELETION_DATE_ATTRIBUTE_NAME = AttributeName.of("deletionDate");
+ static final AttributeName SUBJECT_ATTRIBUTE_VALUE = AttributeName.of("subject");
+
+ private final MailboxId.Factory mailboxIdFactory;
+ private final MessageId.Factory messageIdFactory;
+
+ MailConverter(MailboxId.Factory mailboxIdFactory, MessageId.Factory messageIdFactory) {
+ this.mailboxIdFactory = mailboxIdFactory;
+ this.messageIdFactory = messageIdFactory;
+ }
+
+ MailImpl toMail(DeletedMessage deletedMessage, InputStream inputStream) throws MessagingException {
+ return MailImpl.builder()
+ .name(deletedMessage.getMessageId().serialize())
+ .sender(deletedMessage.getSender())
+ .addRecipients(deletedMessage.getRecipients())
+ .mimeMessage(new MimeMessage(Session.getDefaultInstance(new Properties()), inputStream))
+ .addAttribute(OWNER_ATTRIBUTE_NAME.withValue(SerializableUser.toAttributeValue(deletedMessage.getOwner())))
+ .addAttribute(HAS_ATTACHMENT_ATTRIBUTE_NAME.withValue(AttributeValue.of(deletedMessage.hasAttachment())))
+ .addAttribute(DELIVERY_DATE_ATTRIBUTE_NAME.withValue(SerializableDate.toAttributeValue(deletedMessage.getDeliveryDate())))
+ .addAttribute(DELETION_DATE_ATTRIBUTE_NAME.withValue(SerializableDate.toAttributeValue(deletedMessage.getDeletionDate())))
+ .addAttribute(ORIGIN_MAILBOXES_ATTRIBUTE_NAME.withValue(AttributeValue.of(serializedMailboxIds(deletedMessage))))
+ .addAttribute(SUBJECT_ATTRIBUTE_VALUE.withValue(subjectAttributeValue(deletedMessage)))
+ .build();
+ }
+
+ DeletedMessage fromMail(Mail mail) {
+ return DeletedMessage.builder()
+ .messageId(messageIdFactory.fromString(mail.getName()))
+ .originMailboxes(retrieveMailboxIds(mail))
+ .user(retrieveOwner(mail))
+ .deliveryDate(retrieveDate(mail, DELIVERY_DATE_ATTRIBUTE_NAME))
+ .deletionDate(retrieveDate(mail, DELETION_DATE_ATTRIBUTE_NAME))
+ .sender(mail.getMaybeSender())
+ .recipients(mail.getRecipients())
+ .hasAttachment(retrieveHasAttachment(mail))
+ .subject(retrieveSubject(mail))
+ .build();
+ }
+
+ private ImmutableList<AttributeValue<?>> serializedMailboxIds(DeletedMessage deletedMessage) {
+ return deletedMessage.getOriginMailboxes().stream()
+ .map(MailboxId::serialize)
+ .map(AttributeValue::of)
+ .collect(Guavate.toImmutableList());
+ }
+
+ private AttributeValue<Optional<AttributeValue<String>>> subjectAttributeValue(DeletedMessage deletedMessage) {
+ return AttributeValue.of(deletedMessage.getSubject().map(AttributeValue::of));
+ }
+
+ private Optional<String> retrieveSubject(Mail mail) {
+ return AttributeUtils.getValueAndCastFromMail(mail, SUBJECT_ATTRIBUTE_VALUE, Optional.class)
+ .map(this::retrieveSubject)
+ .orElseThrow(() -> new IllegalArgumentException("mail should have a 'subject' attribute being of type 'Optional<String>"));
+ }
+
+ private Optional<String> retrieveSubject(Optional<?> maybeSubject) {
+ return maybeSubject.map(this::castSubjectToString);
+ }
+
+ private String castSubjectToString(Object object) {
+ Optional<String> optional = Optional.of(object)
+ .filter(obj -> obj instanceof AttributeValue)
+ .map(AttributeValue.class::cast)
+ .flatMap(attributeValue -> attributeValue.valueAs(String.class));
+
+ return optional
+ .orElseThrow(() -> new IllegalArgumentException("mail should have a 'subject' attribute being of type 'Optional<String>"));
+ }
+
+ private boolean retrieveHasAttachment(Mail mail) {
+ return AttributeUtils.getValueAndCastFromMail(mail, HAS_ATTACHMENT_ATTRIBUTE_NAME, Boolean.class)
+ .orElseThrow(() -> new IllegalArgumentException("mail should have a 'hasAttachment' attribute of type boolean"));
+ }
+
+ private ZonedDateTime retrieveDate(Mail mail, AttributeName attributeName) {
+ return AttributeUtils.getValueAndCastFromMail(mail, attributeName, SerializableDate.class)
+ .map(SerializableDate::getValue)
+ .orElseThrow(() -> new IllegalArgumentException("'mail' should have a '" + attributeName.asString() + "' attribute of type SerializableDate"));
+ }
+
+ private User retrieveOwner(Mail mail) {
+ return AttributeUtils.getValueAndCastFromMail(mail, OWNER_ATTRIBUTE_NAME, SerializableUser.class)
+ .map(SerializableUser::getValue)
+ .orElseThrow(() -> new IllegalArgumentException("Supplied email is missing the 'owner' attribute of type SerializableUser"));
+ }
+
+ private List<MailboxId> retrieveMailboxIds(Mail mail) {
+ return AttributeUtils.getValueAndCastFromMail(mail, ORIGIN_MAILBOXES_ATTRIBUTE_NAME, List.class)
+ .map(this::retrieveMailboxIds)
+ .orElseThrow(() -> new IllegalArgumentException("Supplied email is missing the 'originMailboxes' attribute of type List<String>"));
+ }
+
+ private List<MailboxId> retrieveMailboxIds(List<?> list) {
+ return list.stream()
+ .map(this::retrieveMailboxId)
+ .collect(Guavate.toImmutableList());
+ }
+
+ private MailboxId retrieveMailboxId(Object object) {
+ Optional<String> serializedMailboxId = Optional.of(object)
+ .filter(obj -> obj instanceof AttributeValue)
+ .map(AttributeValue.class::cast)
+ .flatMap(attributeValue -> attributeValue.valueAs(String.class));
+
+ return serializedMailboxId
+ .map(mailboxIdFactory::fromString)
+ .orElseThrow(() -> new IllegalArgumentException("Found a non String element in originMailboxes attribute"));
+ }
+}
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableDate.java b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableDate.java
new file mode 100644
index 0000000..f804667
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableDate.java
@@ -0,0 +1,63 @@
+/****************************************************************
+ * 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.vault;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Optional;
+
+import org.apache.mailet.ArbitrarySerializable;
+import org.apache.mailet.AttributeValue;
+
+import com.google.common.base.Preconditions;
+
+public class SerializableDate implements ArbitrarySerializable<SerializableDate> {
+ public static class Factory implements ArbitrarySerializable.Deserializer<SerializableDate> {
+ @Override
+ public Optional<SerializableDate> deserialize(Serializable<SerializableDate> serializable) {
+ return Optional.of(serializable.getValue().value())
+ .filter(String.class::isInstance)
+ .map(String.class::cast)
+ .map(ZonedDateTime::parse)
+ .map(SerializableDate::new);
+ }
+ }
+
+ static AttributeValue<SerializableDate> toAttributeValue(ZonedDateTime date) {
+ return AttributeValue.of(new SerializableDate(date));
+ }
+
+ private final ZonedDateTime value;
+
+ SerializableDate(ZonedDateTime value) {
+ Preconditions.checkNotNull(value);
+
+ this.value = value;
+ }
+
+ @Override
+ public Serializable<SerializableDate> serialize() {
+ return new Serializable<>(AttributeValue.of(value.format(DateTimeFormatter.ISO_ZONED_DATE_TIME)), SerializableDate.Factory.class);
+ }
+
+ public ZonedDateTime getValue() {
+ return value;
+ }
+}
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableUser.java b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableUser.java
new file mode 100644
index 0000000..6327bba
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/main/java/org/apache/james/vault/SerializableUser.java
@@ -0,0 +1,62 @@
+/****************************************************************
+ * 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.vault;
+
+import java.util.Optional;
+
+import org.apache.james.core.User;
+import org.apache.mailet.ArbitrarySerializable;
+import org.apache.mailet.AttributeValue;
+
+import com.google.common.base.Preconditions;
+
+public class SerializableUser implements ArbitrarySerializable<SerializableUser> {
+ public static class Factory implements ArbitrarySerializable.Deserializer<SerializableUser> {
+ @Override
+ public Optional<SerializableUser> deserialize(Serializable<SerializableUser> serializable) {
+ return Optional.of(serializable.getValue().value())
+ .filter(String.class::isInstance)
+ .map(String.class::cast)
+ .map(User::fromUsername)
+ .map(SerializableUser::new);
+ }
+ }
+
+ static AttributeValue<SerializableUser> toAttributeValue(User user) {
+ return AttributeValue.of(new SerializableUser(user));
+ }
+
+ private final User value;
+
+ SerializableUser(User value) {
+ Preconditions.checkNotNull(value);
+
+ this.value = value;
+ }
+
+ @Override
+ public Serializable<SerializableUser> serialize() {
+ return new Serializable<>(AttributeValue.of(value.asString()), Factory.class);
+ }
+
+ public User getValue() {
+ return value;
+ }
+}
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/MailConverterTest.java b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/MailConverterTest.java
new file mode 100644
index 0000000..6644cd5
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/MailConverterTest.java
@@ -0,0 +1,237 @@
+/****************************************************************
+ * 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.vault;
+
+import static org.apache.james.vault.DeletedMessageFixture.CONTENT;
+import static org.apache.james.vault.DeletedMessageFixture.DELETED_MESSAGE;
+import static org.apache.james.vault.DeletedMessageFixture.DELETED_MESSAGE_WITH_SUBJECT;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.io.ByteArrayInputStream;
+
+import org.apache.james.core.MailAddress;
+import org.apache.james.core.MaybeSender;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.inmemory.InMemoryMessageId;
+import org.apache.james.server.core.MailImpl;
+import org.apache.james.util.MimeMessageUtil;
+import org.apache.mailet.AttributeValue;
+import org.apache.mailet.Mail;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.google.common.collect.ImmutableList;
+
+class MailConverterTest {
+
+ private MailConverter mailConverter;
+
+ @BeforeEach
+ void setUp() {
+ mailConverter = new MailConverter(new InMemoryId.Factory(), new InMemoryMessageId.Factory());
+ }
+
+ @Test
+ void convertBackAndForthShouldPreserveDeletedMessageWithSubjectEquality() throws Exception {
+ assertThat(mailConverter.fromMail(mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT))))
+ .isEqualTo(DELETED_MESSAGE_WITH_SUBJECT);
+ }
+
+ @Test
+ void convertBackAndForthShouldPreserveDeletedMessageWithoutSubjectEquality() throws Exception {
+ assertThat(mailConverter.fromMail(mailConverter.toMail(DELETED_MESSAGE, new ByteArrayInputStream(CONTENT))))
+ .isEqualTo(DELETED_MESSAGE);
+ }
+
+ @Test
+ void fromMailShouldReturnDeletedMessageWhenNoRecipient() throws Exception {
+ Mail mail = mailConverter.toMail(DELETED_MESSAGE, new ByteArrayInputStream(CONTENT));
+ mail.setRecipients(ImmutableList.of());
+
+ DeletedMessage deletedMessage = mailConverter.fromMail(mail);
+
+ assertThat(deletedMessage.getRecipients())
+ .isEmpty();
+ }
+
+ @Test
+ void fromMailShouldReturnDeletedMessageWhenNoSender() throws Exception {
+ MailImpl mail = mailConverter.toMail(DELETED_MESSAGE, new ByteArrayInputStream(CONTENT));
+ mail.setSender(MailAddress.nullSender());
+
+ DeletedMessage deletedMessage = mailConverter.fromMail(mail);
+
+ assertThat(deletedMessage.getSender())
+ .isEqualTo(MaybeSender.nullSender());
+ }
+
+ @Test
+ void toMailShouldGenerateAMailWithTheRightContent() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.OWNER_ATTRIBUTE_NAME.withValue(AttributeValue.of("notASerializedUser")));
+
+ assertThat(new ByteArrayInputStream(MimeMessageUtil.asBytes(deletedMessageAsMail.getMessage())))
+ .hasSameContentAs(new ByteArrayInputStream(CONTENT));
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNameIsNotAMessageId() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setName("notAMessageId");
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNoOriginMailboxes() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.removeAttribute(MailConverter.ORIGIN_MAILBOXES_ATTRIBUTE_NAME);
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenOriginMailboxesIsNotAList() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.ORIGIN_MAILBOXES_ATTRIBUTE_NAME.withValue(AttributeValue.of("notAList")));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenOriginMailboxesContainsNonStringElements() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.ORIGIN_MAILBOXES_ATTRIBUTE_NAME.withValue(
+ AttributeValue.of(ImmutableList.of(AttributeValue.of(42)))));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenOriginMailboxesContainsBadFormatStringElements() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.ORIGIN_MAILBOXES_ATTRIBUTE_NAME.withValue(
+ AttributeValue.of(ImmutableList.of(AttributeValue.of("badFormat")))));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNoHasAttachment() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.removeAttribute(MailConverter.HAS_ATTACHMENT_ATTRIBUTE_NAME);
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenHasAttachmentIsNotABoolean() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.HAS_ATTACHMENT_ATTRIBUTE_NAME.withValue(AttributeValue.of("notABoolean")));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNoOwner() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.removeAttribute(MailConverter.OWNER_ATTRIBUTE_NAME);
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenOwnerIsNotASerializedUser() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.OWNER_ATTRIBUTE_NAME.withValue(AttributeValue.of("notASerializedUser")));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNoDeliveryDate() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.removeAttribute(MailConverter.DELIVERY_DATE_ATTRIBUTE_NAME);
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenDeliveryDateIsNotASerializedDate() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.DELIVERY_DATE_ATTRIBUTE_NAME.withValue(AttributeValue.of("notADate")));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenNoDeletionDate() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.removeAttribute(MailConverter.DELETION_DATE_ATTRIBUTE_NAME);
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenDeletionDateIsNotASerializedDate() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.DELETION_DATE_ATTRIBUTE_NAME.withValue(AttributeValue.of("notADate")));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+
+ @Test
+ void fromMailShouldThrowWhenSubjectIsNotAString() throws Exception {
+ Mail deletedMessageAsMail = mailConverter.toMail(DELETED_MESSAGE_WITH_SUBJECT, new ByteArrayInputStream(CONTENT));
+
+ deletedMessageAsMail.setAttribute(MailConverter.SUBJECT_ATTRIBUTE_VALUE.withValue(AttributeValue.of(42)));
+
+ assertThatThrownBy(() -> mailConverter.fromMail(deletedMessageAsMail))
+ .isInstanceOf(IllegalArgumentException.class);
+ }
+}
\ No newline at end of file
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableDateTest.java b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableDateTest.java
new file mode 100644
index 0000000..4efd8bf
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableDateTest.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.vault;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.time.ZonedDateTime;
+
+import org.apache.mailet.AttributeValue;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+class SerializableDateTest {
+ private static final ZonedDateTime DATE = ZonedDateTime.parse("2014-10-30T14:12:00Z");
+
+ @Test
+ void serializeBackAndForthShouldPreserveDate() {
+ JsonNode serializableDate = AttributeValue.of(new SerializableDate(DATE)).toJson();
+
+ ZonedDateTime deserializedDate = AttributeValue.fromJson(serializableDate)
+ .valueAs(SerializableDate.class)
+ .get()
+ .getValue();
+
+ assertThat(deserializedDate).isEqualTo(DATE);
+ }
+
+ @Test
+ void constructorShouldThrowOnNull() {
+ assertThatThrownBy(() -> new SerializableDate(null))
+ .isInstanceOf(NullPointerException.class);
+ }
+}
\ No newline at end of file
diff --git a/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableUserTest.java b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableUserTest.java
new file mode 100644
index 0000000..0d11909
--- /dev/null
+++ b/server/mailrepository/deleted-messages-vault-repository/src/test/java/org/apache/james/vault/SerializableUserTest.java
@@ -0,0 +1,52 @@
+/****************************************************************
+ * 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.vault;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import org.apache.james.core.User;
+import org.apache.mailet.AttributeValue;
+import org.junit.jupiter.api.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+
+class SerializableUserTest {
+ private static final User USER = User.fromUsername("bob@apache.org");
+
+ @Test
+ void serializeBackAndForthShouldPreserveUser() {
+ JsonNode serializableUser = AttributeValue.of(new SerializableUser(USER)).toJson();
+
+ User user = AttributeValue.fromJson(serializableUser)
+ .valueAs(SerializableUser.class)
+ .get()
+ .getValue();
+
+ assertThat(user).isEqualTo(USER);
+ }
+
+ @Test
+ void constructorShouldThrowOnNull() {
+ assertThatThrownBy(() -> new SerializableUser(null))
+ .isInstanceOf(NullPointerException.class);
+ }
+
+}
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org