JAMES-2110 IT for setMessage with keywords
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/37cf8ffc Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/37cf8ffc Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/37cf8ffc Branch: refs/heads/master Commit: 37cf8ffc389219c55793dffc5692f898dad331b1 Parents: a6f1c10 Author: quynhn <[email protected]> Authored: Tue Aug 15 16:46:53 2017 +0700 Committer: Raphael Ouazana <[email protected]> Committed: Thu Aug 24 15:47:28 2017 +0200 ---------------------------------------------------------------------- .../james/mailbox/store/probe/MailboxProbe.java | 2 +- .../james/cli/probe/impl/JmxMailboxProbe.java | 9 +- .../apache/james/modules/MailboxProbeImpl.java | 6 +- .../modules/protocols/JMAPServerModule.java | 2 + .../org/apache/james/utils/MessageIdProbe.java | 50 ++ .../integration/SetMessagesMethodTest.java | 587 +++++++++++++++++-- 6 files changed, 593 insertions(+), 63 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java ---------------------------------------------------------------------- diff --git a/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java index 6878bb5..b96671e 100644 --- a/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java +++ b/mailbox/store/src/main/java/org/apache/james/mailbox/store/probe/MailboxProbe.java @@ -41,7 +41,7 @@ public interface MailboxProbe { void deleteMailbox(String namespace, String user, String name); void importEmlFileToMailbox(String namespace, String user, String name, String emlpath) throws Exception; - + ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate, boolean isRecent, Flags flags) throws MailboxException; http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java ---------------------------------------------------------------------- diff --git a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java index b3b5cc5..ab9005a 100644 --- a/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java +++ b/server/container/cli/src/main/java/org/apache/james/cli/probe/impl/JmxMailboxProbe.java @@ -23,7 +23,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.Date; - import javax.mail.Flags; import javax.management.MalformedObjectNameException; @@ -37,15 +36,15 @@ import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.probe.MailboxProbe; public class JmxMailboxProbe implements MailboxProbe, JmxProbe { - + private final static String MAILBOXCOPIER_OBJECT_NAME = "org.apache.james:type=component,name=mailboxcopier"; private final static String MAILBOXMANAGER_OBJECT_NAME = "org.apache.james:type=component,name=mailboxmanagerbean"; private final static String REINDEXER_OBJECT_NAME = "org.apache.james:type=component,name=reindexerbean"; - + private MailboxCopierManagementMBean mailboxCopierManagement; private MailboxManagerManagementMBean mailboxManagerManagement; private ReIndexerManagementMBean reIndexerManagement; - + public JmxMailboxProbe connect(JmxConnection jmxc) throws IOException { try { mailboxCopierManagement = jmxc.retrieveBean(MailboxCopierManagementMBean.class, MAILBOXCOPIER_OBJECT_NAME); @@ -56,7 +55,7 @@ public class JmxMailboxProbe implements MailboxProbe, JmxProbe { } return this; } - + @Override public void copyMailbox(String srcBean, String dstBean) throws Exception { http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java ---------------------------------------------------------------------- diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java index 73982a7..6dbfb05 100644 --- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java +++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/MailboxProbeImpl.java @@ -155,11 +155,11 @@ public class MailboxProbeImpl implements GuiceProbe, MailboxProbe { mailboxManager.endProcessingRequest(mailboxSession); mailboxSession.close(); } - + @Override - public ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate, boolean isRecent, Flags flags) + public ComposedMessageId appendMessage(String username, MailboxPath mailboxPath, InputStream message, Date internalDate, boolean isRecent, Flags flags) throws MailboxException { - + MailboxSession mailboxSession = mailboxManager.createSystemSession(username); MessageManager messageManager = mailboxManager.getMailbox(mailboxPath, mailboxSession); return messageManager.appendMessage(message, internalDate, mailboxSession, isRecent, flags); http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java ---------------------------------------------------------------------- diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java index aa1cc00..c601c44 100644 --- a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java +++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/modules/protocols/JMAPServerModule.java @@ -26,6 +26,7 @@ import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.james.jmap.JMAPConfiguration; import org.apache.james.jmap.JMAPModule; import org.apache.james.jmap.JMAPServer; +import org.apache.james.utils.MessageIdProbe; import org.apache.james.jmap.crypto.JamesSignatureHandler; import org.apache.james.lifecycle.api.Configurable; import org.apache.james.utils.ConfigurationPerformer; @@ -49,6 +50,7 @@ public class JMAPServerModule extends AbstractModule { install(new JMAPModule()); Multibinder.newSetBinder(binder(), ConfigurationPerformer.class).addBinding().to(JMAPModuleConfigurationPerformer.class); Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(JmapGuiceProbe.class); + Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(MessageIdProbe.class); } @Singleton http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java ---------------------------------------------------------------------- diff --git a/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java new file mode 100644 index 0000000..f6b97a2 --- /dev/null +++ b/server/container/guice/protocols/jmap/src/main/java/org/apache/james/utils/MessageIdProbe.java @@ -0,0 +1,50 @@ +/**************************************************************** + * 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.utils; + +import java.util.List; +import javax.inject.Inject; + +import org.apache.james.mailbox.MailboxManager; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageIdManager; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.FetchGroupImpl; +import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.MessageResult; + +import com.google.common.collect.ImmutableList; + +public class MessageIdProbe implements GuiceProbe { + private final MailboxManager mailboxManager; + private final MessageIdManager messageIdManager; + + @Inject + public MessageIdProbe(MailboxManager mailboxManager, MessageIdManager messageIdManager) { + this.mailboxManager = mailboxManager; + this.messageIdManager = messageIdManager; + } + + public List<MessageResult> getMessages(MessageId messageId, String user) throws MailboxException { + MailboxSession mailboxSession = mailboxManager.createSystemSession(user); + + return messageIdManager.getMessages(ImmutableList.of(messageId), FetchGroupImpl.FULL_CONTENT, mailboxSession); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/37cf8ffc/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java index f372583..3fe34bb 100644 --- a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/methods/integration/SetMessagesMethodTest.java @@ -26,6 +26,7 @@ import static com.jayway.restassured.config.RestAssuredConfig.newConfig; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.equalTo; @@ -38,7 +39,6 @@ import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.collection.IsMapWithSize.aMapWithSize; import static org.hamcrest.collection.IsMapWithSize.anEmptyMap; - import java.io.ByteArrayInputStream; import java.io.IOException; import java.time.ZonedDateTime; @@ -47,16 +47,15 @@ import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; - import javax.mail.Flags; +import javax.mail.Flags.Flag; -import org.apache.commons.io.IOUtils; -import org.apache.http.client.utils.URIBuilder; import org.apache.james.GuiceJamesServer; import org.apache.james.jmap.DefaultMailboxes; import org.apache.james.jmap.HttpJmapAuthentication; import org.apache.james.jmap.api.access.AccessToken; import org.apache.james.jmap.model.mailbox.Role; +import org.apache.james.mailbox.FlagsBuilder; import org.apache.james.mailbox.MailboxListener; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.mailbox.model.Attachment; @@ -64,20 +63,18 @@ import org.apache.james.mailbox.model.ComposedMessageId; import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.mailbox.model.MailboxPath; import org.apache.james.mailbox.model.MessageId; +import org.apache.james.mailbox.model.MessageResult; import org.apache.james.mailbox.store.event.EventFactory; import org.apache.james.mailbox.store.mail.model.Mailbox; import org.apache.james.mailbox.store.probe.MailboxProbe; import org.apache.james.modules.MailboxProbeImpl; +import org.apache.james.utils.MessageIdProbe; import org.apache.james.probe.DataProbe; import org.apache.james.util.ZeroedInputStream; -import org.apache.james.utils.JmapGuiceProbe; import org.apache.james.utils.DataProbeImpl; -import org.hamcrest.Matcher; -import org.hamcrest.Matchers; -import org.junit.After; -import org.junit.Before; -import org.junit.Ignore; -import org.junit.Test; +import org.apache.james.utils.JmapGuiceProbe; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.utils.URIBuilder; import com.google.common.base.Charsets; import com.google.common.collect.ImmutableList; @@ -91,9 +88,16 @@ import com.jayway.restassured.builder.RequestSpecBuilder; import com.jayway.restassured.builder.ResponseSpecBuilder; import com.jayway.restassured.http.ContentType; import com.jayway.restassured.specification.ResponseSpecification; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.junit.After; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; public abstract class SetMessagesMethodTest { + private final static String FORWARDED = "$Forwarded"; private static final int _1MB = 1024*1024; private static final String NAME = "[0][0]"; private static final String ARGUMENTS = "[0][1]"; @@ -103,27 +107,30 @@ public abstract class SetMessagesMethodTest { private static final String USERNAME = "username@" + USERS_DOMAIN; public static final MailboxPath USER_MAILBOX = new MailboxPath(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); private static final String NOT_UPDATED = ARGUMENTS + ".notUpdated"; + private static final String NOT_CREATED = ARGUMENTS + ".notCreated"; private ConditionFactory calmlyAwait; protected abstract GuiceJamesServer createJmapServer(); protected abstract MessageId randomMessageId(); - + protected abstract void await(); private AccessToken accessToken; private GuiceJamesServer jmapServer; private MailboxProbe mailboxProbe; private DataProbe dataProbe; - + private MessageIdProbe messageProbe; + @Before public void setup() throws Throwable { jmapServer = createJmapServer(); jmapServer.start(); mailboxProbe = jmapServer.getProbe(MailboxProbeImpl.class); dataProbe = jmapServer.getProbe(DataProbeImpl.class); - + messageProbe = jmapServer.getProbe(MessageIdProbe.class); + RestAssured.requestSpecification = new RequestSpecBuilder() .setContentType(ContentType.JSON) .setAccept(ContentType.JSON) @@ -161,7 +168,7 @@ public abstract class SetMessagesMethodTest { public void teardown() { jmapServer.stop(); } - + private String getOutboxId(AccessToken accessToken) { return getMailboxId(accessToken, Role.OUTBOX); } @@ -172,7 +179,7 @@ public abstract class SetMessagesMethodTest { .map(x -> x.get("id")) .findFirst().get(); } - + private List<Map<String, String>> getAllMailboxesIds(AccessToken accessToken) { return with() .header("Authorization", accessToken.serialize()) @@ -185,7 +192,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullAccountId() throws Exception { + public void setMessagesShouldReturnAnErrorNotSupportedWhenRequestContainsNonNullAccountId() throws Exception { given() .header("Authorization", accessToken.serialize()) .body("[[\"setMessages\", {\"accountId\": \"1\"}, \"#0\"]]") @@ -199,7 +206,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullIfInState() throws Exception { + public void setMessagesShouldReturnAnErrorNotSupportedWhenRequestContainsNonNullIfInState() throws Exception { given() .header("Authorization", accessToken.serialize()) .body("[[\"setMessages\", {\"ifInState\": \"1\"}, \"#0\"]]") @@ -369,7 +376,7 @@ public abstract class SetMessagesMethodTest { randomMessageId().serialize(), message3.getMessageId().serialize())) .post("/jmap"); - + // Then given() .header("Authorization", accessToken.serialize()) @@ -396,7 +403,7 @@ public abstract class SetMessagesMethodTest { await(); String serializedMessageId = message.getMessageId().serialize(); - + // When given() .header("Authorization", accessToken.serialize()) @@ -409,6 +416,322 @@ public abstract class SetMessagesMethodTest { .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId)); } + @Test + public void setMessagesWithUpdateShouldReturnAnErrorWhenBothIsFlagAndKeywordsArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags()); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"isUnread\" : false, \"keywords\": {\"$Seen\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .body(NOT_UPDATED, hasKey(messageId)) + .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties")) + .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not support keyword and is* at the same time")) + .body(ARGUMENTS + ".updated", hasSize(0)); + } + + @Test + public void setMessagesShouldUpdateKeywordsWhenKeywordsArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags()); + await(); + + String serializedMessageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Flagged\": true} } } }, \"#0\"]]", serializedMessageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId)); + + with() + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]") + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)) + .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true)) + .body(ARGUMENTS + ".list[0].keywords.$Flagged", equalTo(true)); + } + + @Test + public void setMessagesShouldAddForwardedFlagWhenKeywordsWithForwardedIsPassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags()); + await(); + + String serializedMessageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Forwarded\": true} } } }, \"#0\"]]", serializedMessageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId)); + + with() + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]") + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)) + .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true)) + .body(ARGUMENTS + ".list[0].keywords.$Forwarded", equalTo(true)); + } + + @Test + public void setMessagesShouldRemoveForwardedFlagWhenKeywordsWithoutForwardedIsPassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + Flags flags = FlagsBuilder.builder() + .add(Flag.SEEN) + .add(FORWARDED) + .build(); + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, flags); + await(); + + String serializedMessageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true} } } }, \"#0\"]]", serializedMessageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(serializedMessageId)); + + with() + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + serializedMessageId + "\"]}, \"#0\"]]") + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)) + .body(ARGUMENTS + ".list[0].keywords.$Seen", equalTo(true)); + } + + @Test + public void setMessagesShouldReturnAnErrorWhenKeywordsWithAddingDraftArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED)); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Draft\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .body(NOT_UPDATED, hasKey(messageId)) + .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties")) + .body(NOT_UPDATED + "[\""+messageId+"\"].properties[0]", equalTo("keywords")) + .body(NOT_UPDATED + "[\""+messageId+"\"].description", equalTo("keywords: Cannot add or remove draft flag")) + .body(ARGUMENTS + ".updated", hasSize(0)); + } + + @Test + public void setMessagesShouldReturnAnErrorWhenKeywordsWithDeletedArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED)); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Deleted\" : true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .body(NOT_UPDATED, hasKey(messageId)) + .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties")) + .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not allow to update 'Deleted' or 'Recent' flag")) + .body(ARGUMENTS + ".updated", hasSize(0)); + } + + @Test + public void setMessagesShouldReturnAnErrorWhenKeywordsWithRecentArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.ANSWERED)); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Recent\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .body(NOT_UPDATED, hasKey(messageId)) + .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties")) + .body(NOT_UPDATED + "[\""+messageId+"\"].description", containsString("Does not allow to update 'Deleted' or 'Recent' flag")) + .body(ARGUMENTS + ".updated", hasSize(0)); + } + + @Test + public void setMessagesShouldNotChangeOriginDeletedFlag() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.DELETED)); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Forwarded\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(messageId)); + + List<MessageResult> messages = messageProbe.getMessages(message.getMessageId(), USERNAME); + Flags expectedFlags = FlagsBuilder.builder() + .add(Flag.ANSWERED, Flag.DELETED) + .add(FORWARDED) + .build(); + + assertThat(messages) + .hasSize(1) + .extracting(MessageResult::getFlags) + .containsOnly(expectedFlags); + } + + @Test + public void setMessagesShouldNotChangeOriginRecentFlag() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + Flags flags = FlagsBuilder.builder() + .add(Flag.DELETED, Flag.RECENT) + .build(); + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, flags); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Answered\": true, \"$Forwarded\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(messageId)); + + List<MessageResult> messages = messageProbe.getMessages(message.getMessageId(), USERNAME); + + Flags expectedFlags = FlagsBuilder.builder() + .add(Flag.ANSWERED, Flag.DELETED, Flag.RECENT) + .add(FORWARDED) + .build(); + + assertThat(messages) + .hasSize(1) + .extracting(MessageResult::getFlags) + .containsOnly(expectedFlags); + } + + @Test + public void setMessagesShouldReturnAnErrorWhenKeywordsWithRemoveDraftArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags(Flags.Flag.DRAFT)); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .body(NOT_UPDATED, hasKey(messageId)) + .body(NOT_UPDATED + "[\""+messageId+"\"].type", equalTo("invalidProperties")) + .body(NOT_UPDATED + "[\""+messageId+"\"].properties[0]", equalTo("keywords")) + .body(NOT_UPDATED + "[\""+messageId+"\"].description", equalTo("keywords: Cannot add or remove draft flag")) + .body(ARGUMENTS + ".updated", hasSize(0)); + } + + @Test + public void setMessagesShouldReturnNewKeywordsWhenKeywordsArePassedToRemoveAndAddFlag() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + Flags currentFlags = FlagsBuilder.builder() + .add(Flag.DRAFT, Flag.ANSWERED) + .build(); + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, currentFlags); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Draft\": true, \"$Flagged\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .spec(getSetMessagesUpdateOKResponseAssertions(messageId)); + + with() + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + messageId + "\"]}, \"#0\"]]") + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)) + .body(ARGUMENTS + ".list[0].keywords.$Draft", equalTo(true)) + .body(ARGUMENTS + ".list[0].keywords.$Flagged", equalTo(true)); + } + private ResponseSpecification getSetMessagesUpdateOKResponseAssertions(String messageId) { ResponseSpecBuilder builder = new ResponseSpecBuilder() .expectStatusCode(200) @@ -656,7 +979,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldReturnNotFoundWhenUpdateUnknownMessage() { + public void setMessagesShouldReturnNotFoundWhenUpdateUnknownMessage() { mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); String nonExistingMessageId = randomMessageId().serialize(); @@ -677,7 +1000,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldReturnCreatedMessageWhenSendingMessage() { + public void setMessagesShouldReturnCreatedMessageWhenSendingMessage() { String messageCreationId = "creationId1337"; String fromAddress = USERNAME; String requestBody = "[" + @@ -717,10 +1040,10 @@ public abstract class SetMessagesMethodTest { hasEntry(equalTo("threadId"), not(isEmptyOrNullString())), hasEntry(equalTo("size"), not(isEmptyOrNullString())) ))) - // assert that message flags are all unset + // assert that message FLAGS are all unset .body(ARGUMENTS + ".created", hasEntry(equalTo(messageCreationId), Matchers.allOf( hasEntry(equalTo("isDraft"), equalTo(false)), - hasEntry(equalTo("isUnread"), equalTo(false)), + hasEntry(equalTo("isUnread"), equalTo(true)), hasEntry(equalTo("isFlagged"), equalTo(false)), hasEntry(equalTo("isAnswered"), equalTo(false)) ))) @@ -728,7 +1051,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsNull() { + public void setMessagesShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsNull() { String messageCreationId = "creationId1337"; String fromAddress = USERNAME; String requestBody = "[" + @@ -762,7 +1085,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsEmpty() { + public void setMessagesShouldReturnCreatedMessageWithEmptySubjectWhenSubjectIsEmpty() { String messageCreationId = "creationId1337"; String fromAddress = USERNAME; String requestBody = "[" + @@ -794,9 +1117,9 @@ public abstract class SetMessagesMethodTest { .body(ARGUMENTS + ".created", hasKey(messageCreationId)) .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].subject", equalTo("")); } - + @Test - public void setMessageShouldReturnCreatedMessageWithNonASCIICharactersInSubjectWhenPresent() { + public void setMessagesShouldReturnCreatedMessageWithNonASCIICharactersInSubjectWhenPresent() { String messageCreationId = "creationId1337"; String fromAddress = USERNAME; String requestBody = "[" + @@ -830,7 +1153,77 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldSupportArbitraryMessageId() { + public void setMessageWithCreatedMessageShouldReturnAnErrorWhenBothIsFlagAndKeywordsPresent() { + String messageCreationId = "creationId1337"; + String fromAddress = USERNAME; + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"" + messageCreationId + "\" : {" + + " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," + + " \"to\": [{ \"name\": \"BOB\", \"email\": \"[email protected]\"}]," + + " \"subject\": \"subject\"," + + " \"isDraft\": true," + + " \"keywords\": {\"$Draft\": true}," + + " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + + given() + .header("Authorization", accessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("error")) + .body(ARGUMENTS + ".type", equalTo("invalidArguments")) + .body(ARGUMENTS + ".description", containsString("Does not support keyword and is* at the same time")); + } + + @Test + public void setMessageWithCreatedMessageShouldSupportKeywordsForFlags() { + String messageCreationId = "creationId1337"; + String fromAddress = USERNAME; + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"" + messageCreationId + "\" : {" + + " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," + + " \"to\": [{ \"name\": \"BOB\", \"email\": \"[email protected]\"}]," + + " \"subject\": \"subject\"," + + " \"keywords\": {\"$Draft\": true, \"$Flagged\": true}," + + " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + + given() + .header("Authorization", accessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".notCreated", aMapWithSize(0)) + .body(ARGUMENTS + ".created", aMapWithSize(1)) + .body(ARGUMENTS + ".created", hasKey(messageCreationId)) + .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Draft", equalTo(true)) + .body(ARGUMENTS + ".created[\""+messageCreationId+"\"].keywords.$Flagged", equalTo(true)) + ; + } + @Test + public void setMessagesShouldSupportArbitraryMessageId() { String messageCreationId = "1717fcd1-603e-44a5-b2a6-1234dbcd5723"; String fromAddress = USERNAME; String requestBody = "[" + @@ -1325,7 +1718,7 @@ public abstract class SetMessagesMethodTest { .log().ifValidationFails() .statusCode(200) .body(SECOND_NAME, equalTo("messages")) - .body(SECOND_ARGUMENTS + ".list", hasSize(1)) + .body(SECOND_ARGUMENTS + ".list", hasSize(1)) .body(SECOND_ARGUMENTS + ".list[0].bcc", empty()); } @@ -1380,7 +1773,7 @@ public abstract class SetMessagesMethodTest { .log().ifValidationFails() .statusCode(200) .body(SECOND_NAME, equalTo("messages")) - .body(SECOND_ARGUMENTS + ".list", hasSize(1)) + .body(SECOND_ARGUMENTS + ".list", hasSize(1)) .body(SECOND_ARGUMENTS + ".list[0].bcc", hasSize(1)); } @@ -1439,7 +1832,7 @@ public abstract class SetMessagesMethodTest { .log().ifValidationFails() .statusCode(200) .body(SECOND_NAME, equalTo("messages")) - .body(SECOND_ARGUMENTS + ".list", hasSize(1)) + .body(SECOND_ARGUMENTS + ".list", hasSize(1)) .body(SECOND_ARGUMENTS + ".list[0].bcc", empty()); } @@ -1455,7 +1848,7 @@ public abstract class SetMessagesMethodTest { .body(NAME, equalTo("messageList")) .body(ARGUMENTS + ".messageIds", hasSize(1)); return true; - + } catch (AssertionError e) { return false; } @@ -1591,7 +1984,7 @@ public abstract class SetMessagesMethodTest { .body(ARGUMENTS + ".created", aMapWithSize(0)); } - + private boolean isHtmlMessageReceived(AccessToken recipientToken) { try { with() @@ -1609,7 +2002,7 @@ public abstract class SetMessagesMethodTest { return false; } } - + @Test public void setMessagesShouldSendAReadableTextPlusHtmlMessage() throws Exception { // Recipient @@ -2152,7 +2545,7 @@ public abstract class SetMessagesMethodTest { .body(ARGUMENTS + ".list", hasSize(1)) .body(firstMessage + ".mailboxIds", containsInAnyOrder(trashId, mailboxId)); } - + @Test public void setMessagesShouldReturnAttachmentsNotFoundWhenBlobIdDoesntExist() throws Exception { String messageCreationId = "creationId"; @@ -2430,7 +2823,7 @@ public abstract class SetMessagesMethodTest { String thirdAttachment = message + ".attachments[2]"; String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2438,7 +2831,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + given() .header("Authorization", accessToken.serialize()) .body("[[\"getMessages\", {\"ids\": [\"" + receivedMessageId + "\"]}, \"#0\"]]") @@ -2479,7 +2872,7 @@ public abstract class SetMessagesMethodTest { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49, 50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99, 100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127}; - + Attachment attachment = Attachment.builder() .bytes(rawBytes) .type("application/octet-stream") @@ -2521,7 +2914,7 @@ public abstract class SetMessagesMethodTest { calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2529,7 +2922,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + String firstMessage = ARGUMENTS + ".list[0]"; String firstAttachment = firstMessage + ".attachments[0]"; given() @@ -2593,7 +2986,7 @@ public abstract class SetMessagesMethodTest { calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2601,7 +2994,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + String firstMessage = ARGUMENTS + ".list[0]"; String firstAttachment = firstMessage + ".attachments[0]"; given() @@ -2634,7 +3027,7 @@ public abstract class SetMessagesMethodTest { .body(NAME, equalTo("messageList")) .body(ARGUMENTS + ".messageIds", hasSize(1)); return true; - + } catch (AssertionError e) { return false; } @@ -2685,7 +3078,7 @@ public abstract class SetMessagesMethodTest { calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2693,7 +3086,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + String firstMessage = ARGUMENTS + ".list[0]"; String firstAttachment = firstMessage + ".attachments[0]"; given() @@ -2758,7 +3151,7 @@ public abstract class SetMessagesMethodTest { calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2766,7 +3159,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + String firstMessage = ARGUMENTS + ".list[0]"; String firstAttachment = firstMessage + ".attachments[0]"; given() @@ -2827,7 +3220,7 @@ public abstract class SetMessagesMethodTest { calmlyAwait.atMost(30, TimeUnit.SECONDS).until( () -> isAnyMessageFoundInInbox(accessToken)); String inboxId = getMailboxId(accessToken, Role.INBOX); - String receivedMessageId = + String receivedMessageId = with() .header("Authorization", accessToken.serialize()) .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + inboxId + "\"]}}, \"#0\"]]") @@ -2835,7 +3228,7 @@ public abstract class SetMessagesMethodTest { .then() .extract() .path(ARGUMENTS + ".messageIds[0]"); - + String firstMessage = ARGUMENTS + ".list[0]"; String firstAttachment = firstMessage + ".attachments[0]"; given() @@ -2856,7 +3249,7 @@ public abstract class SetMessagesMethodTest { .body(firstAttachment + ".size", equalTo((int) attachment.getSize())); } @Test - public void setMessageShouldVerifyHeaderOfMessageInInbox() throws Exception { + public void setMessagesShouldVerifyHeaderOfMessageInInbox() throws Exception { String toUsername = "username1@" + USERS_DOMAIN; String password = "password"; dataProbe.addUser(toUsername, password); @@ -2893,7 +3286,7 @@ public abstract class SetMessagesMethodTest { } @Test - public void setMessageShouldVerifyHeaderOfMessageInSent() throws Exception { + public void setMessagesShouldVerifyHeaderOfMessageInSent() throws Exception { String toUsername = "username1@" + USERS_DOMAIN; String password = "password"; dataProbe.addUser(toUsername, password); @@ -2958,8 +3351,7 @@ public abstract class SetMessagesMethodTest { .statusCode(200) .body(ARGUMENTS + ".messageIds", hasSize(1)) .body(SECOND_NAME, equalTo("messages")) - .body(SECOND_ARGUMENTS + ".list[0]", hasEntry(equalTo("headers"), allHeadersMatcher(expectedHeaders))) - ; + .body(SECOND_ARGUMENTS + ".list[0]", hasEntry(equalTo("headers"), allHeadersMatcher(expectedHeaders))); return true; } catch(AssertionError e) { e.printStackTrace(); @@ -3210,4 +3602,91 @@ public abstract class SetMessagesMethodTest { .body(secondAttachment + ".cid", nullValue()) .body(secondAttachment + ".isInline", equalTo(true)); } + + @Test + public void setMessageWithUpdateShouldBeOKWhenKeywordsWithCustomFlagArePassed() throws MailboxException { + mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, "mailbox"); + + ComposedMessageId message = mailboxProbe.appendMessage(USERNAME, USER_MAILBOX, + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes(Charsets.UTF_8)), new Date(), false, new Flags()); + await(); + + String messageId = message.getMessageId().serialize(); + + given() + .header("Authorization", accessToken.serialize()) + .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"keywords\": {\"$Seen\": true, \"$Unknown\": true} } } }, \"#0\"]]", messageId)) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .spec(getSetMessagesUpdateOKResponseAssertions(messageId)); + } + + @Test + public void setMessageWithCreationShouldBeOKWhenKeywordsWithCustomFlagArePassed() { + String messageCreationId = "creationId1337"; + String fromAddress = USERNAME; + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"" + messageCreationId + "\" : {" + + " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," + + " \"to\": [{ \"name\": \"BOB\", \"email\": \"[email protected]\"}]," + + " \"subject\": \"subject\"," + + " \"keywords\": {\"$Draft\": true, \"$Unknown\": true}," + + " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + + given() + .header("Authorization", accessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".notCreated", aMapWithSize(0)) + .body(ARGUMENTS + ".created", aMapWithSize(1)); + } + + @Test + public void setMessageWithCreationShouldThrowWhenKeywordsWithUnsupportedArePassed() { + String messageCreationId = "creationId1337"; + String fromAddress = USERNAME; + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"" + messageCreationId + "\" : {" + + " \"from\": { \"name\": \"Me\", \"email\": \"" + fromAddress + "\"}," + + " \"to\": [{ \"name\": \"BOB\", \"email\": \"[email protected]\"}]," + + " \"subject\": \"subject\"," + + " \"keywords\": {\"$Draft\": true, \"$Deleted\": true}," + + " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + + given() + .header("Authorization", accessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap") + .then() + .log().ifValidationFails() + .statusCode(200) + .body(NAME, equalTo("error")) + .body(ARGUMENTS + ".type", equalTo("invalidArguments")) + .body(ARGUMENTS + ".description", containsString("Does not allow to update 'Deleted' or 'Recent' flag")); + } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
