JAMES-1675 Implement SetMessages: destroy
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/6665a49e Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/6665a49e Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/6665a49e Branch: refs/heads/master Commit: 6665a49e61bb241839da39738d6b798bdd8a572c Parents: 7fca1ee Author: Antoine Duprat <[email protected]> Authored: Wed Jan 20 16:53:16 2016 +0100 Committer: Antoine Duprat <[email protected]> Committed: Mon Feb 8 15:00:00 2016 +0100 ---------------------------------------------------------------------- .../org/apache/james/jmap/MethodsModule.java | 2 + .../protocols/jmap-integration-testing/pom.xml | 6 + .../jmap/methods/SetMessagesMethodTest.java | 287 +++++++++++++++++++ .../CassandraSetMessagesMethodTest.java | 35 +++ .../exceptions/MessageNotFoundException.java | 23 ++ .../james/jmap/methods/SetMessagesMethod.java | 145 ++++++++++ .../org/apache/james/jmap/model/MessageId.java | 3 +- .../org/apache/james/jmap/model/SetError.java | 80 ++++++ .../james/jmap/model/SetMessagesRequest.java | 126 ++++++++ .../james/jmap/model/SetMessagesResponse.java | 188 ++++++++++++ .../apache/james/jmap/model/SetErrorTest.java | 59 ++++ .../jmap/model/SetMessagesRequestTest.java | 96 +++++++ .../jmap/model/SetMessagesResponseTest.java | 86 ++++++ 13 files changed, 1135 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java ---------------------------------------------------------------------- diff --git a/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java b/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java index c36619d..71e2dcd 100644 --- a/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java +++ b/server/container/cassandra-guice/src/main/java/org/apache/james/jmap/MethodsModule.java @@ -28,6 +28,7 @@ import org.apache.james.jmap.methods.JmapRequestParserImpl; import org.apache.james.jmap.methods.JmapResponseWriter; import org.apache.james.jmap.methods.JmapResponseWriterImpl; import org.apache.james.jmap.methods.Method; +import org.apache.james.jmap.methods.SetMessagesMethod; import org.apache.james.mailbox.cassandra.CassandraId; import com.google.inject.AbstractModule; @@ -50,6 +51,7 @@ public class MethodsModule extends AbstractModule { methods.addBinding().to(new TypeLiteral<GetMailboxesMethod<CassandraId>>(){}); methods.addBinding().to(new TypeLiteral<GetMessageListMethod<CassandraId>>(){}); methods.addBinding().to(new TypeLiteral<GetMessagesMethod<CassandraId>>(){}); + methods.addBinding().to(new TypeLiteral<SetMessagesMethod<CassandraId>>(){}); } } http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap-integration-testing/pom.xml ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/pom.xml b/server/protocols/jmap-integration-testing/pom.xml index 655c7e9..b3ada4c 100644 --- a/server/protocols/jmap-integration-testing/pom.xml +++ b/server/protocols/jmap-integration-testing/pom.xml @@ -201,6 +201,12 @@ <version>${cassandra-unit.version}</version> <scope>test</scope> </dependency> + <dependency> + <groupId>org.hamcrest</groupId> + <artifactId>java-hamcrest</artifactId> + <version>2.0.0.0</version> + <scope>test</scope> + </dependency> </dependencies> <build> <plugins> http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/SetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/SetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/SetMessagesMethodTest.java new file mode 100644 index 0000000..bbe2e57 --- /dev/null +++ b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/SetMessagesMethodTest.java @@ -0,0 +1,287 @@ +/**************************************************************** + * 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.jmap.methods; + +import static com.jayway.restassured.RestAssured.given; +import static com.jayway.restassured.config.EncoderConfig.encoderConfig; +import static com.jayway.restassured.config.RestAssuredConfig.newConfig; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasEntry; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.collection.IsMapWithSize.aMapWithSize; +import static org.hamcrest.collection.IsMapWithSize.anEmptyMap; + +import java.io.ByteArrayInputStream; +import java.util.Date; + +import javax.mail.Flags; + +import org.apache.james.backends.cassandra.EmbeddedCassandra; +import org.apache.james.jmap.JmapAuthentication; +import org.apache.james.jmap.JmapServer; +import org.apache.james.jmap.api.access.AccessToken; +import org.apache.james.mailbox.elasticsearch.EmbeddedElasticSearch; +import org.apache.james.mailbox.model.MailboxConstants; +import org.apache.james.mailbox.model.MailboxPath; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.RuleChain; +import org.junit.rules.TemporaryFolder; + +import com.google.common.base.Charsets; +import com.google.common.collect.ImmutableMap; +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.http.ContentType; + +public abstract class SetMessagesMethodTest { + + private static final String NAME = "[0][0]"; + private static final String ARGUMENTS = "[0][1]"; + + private TemporaryFolder temporaryFolder = new TemporaryFolder(); + private EmbeddedElasticSearch embeddedElasticSearch = new EmbeddedElasticSearch(temporaryFolder); + private EmbeddedCassandra cassandra = EmbeddedCassandra.createStartServer(); + private JmapServer jmapServer = jmapServer(temporaryFolder, embeddedElasticSearch, cassandra); + + protected abstract JmapServer jmapServer(TemporaryFolder temporaryFolder, EmbeddedElasticSearch embeddedElasticSearch, EmbeddedCassandra cassandra); + + @Rule + public RuleChain chain = RuleChain + .outerRule(temporaryFolder) + .around(embeddedElasticSearch) + .around(jmapServer); + + private AccessToken accessToken; + private String username; + + @Before + public void setup() throws Exception { + RestAssured.port = jmapServer.getPort(); + RestAssured.config = newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)); + + String domain = "domain.tld"; + username = "username@" + domain; + String password = "password"; + jmapServer.serverProbe().addDomain(domain); + jmapServer.serverProbe().addUser(username, password); + jmapServer.serverProbe().createMailbox("#private", "username", "inbox"); + accessToken = JmapAuthentication.authenticateJamesUser(username, password); + } + + @Test + public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullAccountId() throws Exception { + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"accountId\": \"1\"}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("error")) + .body(ARGUMENTS + ".type", equalTo("Not yet implemented")); + } + + @Test + public void setMessagesShouldReturnErrorNotSupportedWhenRequestContainsNonNullIfInState() throws Exception { + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"ifInState\": \"1\"}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("error")) + .body(ARGUMENTS + ".type", equalTo("Not yet implemented")); + } + + @Test + public void setMessagesShouldReturnNotDestroyedWhenUnknownMailbox() throws Exception { + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|unknown|1\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".destroyed", empty()) + .body(ARGUMENTS + ".notDestroyed", hasEntry(username + "|unknown|1", + ImmutableMap.of("type", "anErrorOccurred", + "description", "An error occurred while deleting message " + username + "|unknown|1"))); + } + + @Test + public void setMessagesShouldReturnNotDestroyedWhenNoMatchingMessage() throws Exception { + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|mailbox|12345\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".destroyed", empty()) + .body(ARGUMENTS + ".notDestroyed", hasEntry(username + "|mailbox|12345", + ImmutableMap.of("type", "notFound", + "description", "The message " + username + "|mailbox|12345 can't be found"))); + } + + @Test + public void setMessagesShouldReturnDestroyedWhenMatchingMessage() throws Exception { + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + embeddedElasticSearch.awaitForElasticSearch(); + + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|mailbox|1\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".notDestroyed", anEmptyMap()) + .body(ARGUMENTS + ".destroyed", hasSize(1)) + .body(ARGUMENTS + ".destroyed", contains(username + "|mailbox|1")); + } + + @Test + public void setMessagesShouldDeleteMessageWhenMatchingMessage() throws Exception { + // Given + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + embeddedElasticSearch.awaitForElasticSearch(); + + // When + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|mailbox|1\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200); + + // Then + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + username + "|mailbox|1\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", empty()); + } + + @Test + public void setMessagesShouldReturnDestroyedNotDestroyWhenMixed() throws Exception { + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test2\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test3\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + embeddedElasticSearch.awaitForElasticSearch(); + + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|mailbox|1\", \"" + username + "|mailbox|4\", \"" + username + "|mailbox|3\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messagesSet")) + .body(ARGUMENTS + ".destroyed", hasSize(2)) + .body(ARGUMENTS + ".notDestroyed", aMapWithSize(1)) + .body(ARGUMENTS + ".destroyed", contains(username + "|mailbox|1", username + "|mailbox|3")) + .body(ARGUMENTS + ".notDestroyed", hasEntry(username + "|mailbox|4", + ImmutableMap.of("type", "notFound", + "description", "The message " + username + "|mailbox|4 can't be found"))); + } + + @Test + public void setMessagesShouldDeleteMatchingMessagesWhenMixed() throws Exception { + // Given + jmapServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, username, "mailbox"); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test2\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + + jmapServer.serverProbe().appendMessage(username, new MailboxPath(MailboxConstants.USER_NAMESPACE, username, "mailbox"), + new ByteArrayInputStream("Subject: test3\r\n\r\ntestmail".getBytes()), new Date(), false, new Flags()); + embeddedElasticSearch.awaitForElasticSearch(); + + // When + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"setMessages\", {\"destroy\": [\"" + username + "|mailbox|1\", \"" + username + "|mailbox|4\", \"" + username + "|mailbox|3\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200); + + // Then + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"getMessages\", {\"ids\": [\"" + username + "|mailbox|1\", \"" + username + "|mailbox|2\", \"" + username + "|mailbox|3\"]}, \"#0\"]]") + .when() + .post("/jmap") + .then() + .statusCode(200) + .body(NAME, equalTo("messages")) + .body(ARGUMENTS + ".list", hasSize(1)); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/cassandra/CassandraSetMessagesMethodTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/cassandra/CassandraSetMessagesMethodTest.java b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/cassandra/CassandraSetMessagesMethodTest.java new file mode 100644 index 0000000..6d48f4b --- /dev/null +++ b/server/protocols/jmap-integration-testing/src/test/java/org/apache/james/jmap/methods/cassandra/CassandraSetMessagesMethodTest.java @@ -0,0 +1,35 @@ +/**************************************************************** + * 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.jmap.methods.cassandra; + +import org.apache.james.backends.cassandra.EmbeddedCassandra; +import org.apache.james.jmap.JmapServer; +import org.apache.james.jmap.cassandra.CassandraJmapServer; +import org.apache.james.jmap.methods.SetMessagesMethodTest; +import org.apache.james.mailbox.elasticsearch.EmbeddedElasticSearch; +import org.junit.rules.TemporaryFolder; + +public class CassandraSetMessagesMethodTest extends SetMessagesMethodTest { + + @Override + protected JmapServer jmapServer(TemporaryFolder temporaryFolder, EmbeddedElasticSearch embeddedElasticSearch, EmbeddedCassandra cassandra) { + return new CassandraJmapServer(CassandraJmapServer.defaultOverrideModule(temporaryFolder, embeddedElasticSearch, cassandra)); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageNotFoundException.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageNotFoundException.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageNotFoundException.java new file mode 100644 index 0000000..6b09819 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/exceptions/MessageNotFoundException.java @@ -0,0 +1,23 @@ +/**************************************************************** + * 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.jmap.exceptions; + +public class MessageNotFoundException extends Exception { +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesMethod.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesMethod.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesMethod.java new file mode 100644 index 0000000..ebdaf77 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/methods/SetMessagesMethod.java @@ -0,0 +1,145 @@ +/**************************************************************** + * 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.jmap.methods; + +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Stream; + +import javax.inject.Inject; + +import org.apache.james.jmap.exceptions.MessageNotFoundException; +import org.apache.james.jmap.model.ClientId; +import org.apache.james.jmap.model.MessageId; +import org.apache.james.jmap.model.SetError; +import org.apache.james.jmap.model.SetMessagesRequest; +import org.apache.james.jmap.model.SetMessagesResponse; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.store.MailboxSessionMapperFactory; +import org.apache.james.mailbox.store.mail.MailboxMapperFactory; +import org.apache.james.mailbox.store.mail.MessageMapper; +import org.apache.james.mailbox.store.mail.MessageMapper.FetchType; +import org.apache.james.mailbox.store.mail.model.Mailbox; +import org.apache.james.mailbox.store.mail.model.MailboxId; +import org.apache.james.mailbox.store.mail.model.MailboxMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; + +public class SetMessagesMethod<Id extends MailboxId> implements Method { + + private static final int LIMIT_BY_ONE = 1; + private static final Logger LOGGER = LoggerFactory.getLogger(SetMessagesMethod.class); + private static final Method.Request.Name METHOD_NAME = Method.Request.name("setMessages"); + private static final Method.Response.Name RESPONSE_NAME = Method.Response.name("messagesSet"); + + private final MailboxMapperFactory<Id> mailboxMapperFactory; + private final MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory; + + @Inject + @VisibleForTesting SetMessagesMethod(MailboxMapperFactory<Id> mailboxMapperFactory, MailboxSessionMapperFactory<Id> mailboxSessionMapperFactory) { + this.mailboxMapperFactory = mailboxMapperFactory; + this.mailboxSessionMapperFactory = mailboxSessionMapperFactory; + } + + @Override + public Method.Request.Name requestHandled() { + return METHOD_NAME; + } + + @Override + public Class<? extends JmapRequest> requestType() { + return SetMessagesRequest.class; + } + + public Stream<JmapResponse> process(JmapRequest request, ClientId clientId, MailboxSession mailboxSession) { + Preconditions.checkArgument(request instanceof SetMessagesRequest); + try { + return Stream.of( + JmapResponse.builder().clientId(clientId) + .response(setMessagesResponse((SetMessagesRequest) request, mailboxSession)) + .responseName(RESPONSE_NAME) + .build()); + } catch (MailboxException e) { + return Stream.of( + JmapResponse.builder().clientId(clientId) + .error() + .responseName(RESPONSE_NAME) + .build()); + } + } + + private SetMessagesResponse setMessagesResponse(SetMessagesRequest request, MailboxSession mailboxSession) throws MailboxException { + SetMessagesResponse.Builder responseBuilder = SetMessagesResponse.builder(); + processDestroy(request.getDestroy(), mailboxSession, responseBuilder); + return responseBuilder.build(); + } + + private void processDestroy(List<MessageId> messageIds, MailboxSession mailboxSession, SetMessagesResponse.Builder responseBuilder) throws MailboxException { + MessageMapper<Id> messageMapper = mailboxSessionMapperFactory.createMessageMapper(mailboxSession); + Consumer<? super MessageId> delete = delete(messageMapper, mailboxSession, responseBuilder); + + messageIds.stream() + .forEach(delete); + } + + private Consumer<? super MessageId> delete(MessageMapper<Id> messageMapper, MailboxSession mailboxSession, SetMessagesResponse.Builder responseBuilder) { + return (messageId) -> { + try { + Mailbox<Id> mailbox = mailboxMapperFactory + .getMailboxMapper(mailboxSession) + .findMailboxByPath(messageId.getMailboxPath(mailboxSession)); + + MailboxMessage<Id> mailboxMessage = getMailboxMessage(messageMapper, messageId, mailbox); + + messageMapper.delete(mailbox, mailboxMessage); + responseBuilder.destroyed(messageId); + } catch (MessageNotFoundException e) { + responseBuilder.notDestroyed(messageId, + SetError.builder() + .type("notFound") + .description("The message " + messageId.serialize() + " can't be found") + .build()); + } catch (MailboxException e) { + LOGGER.error("An error occurred when deleting a message", e); + responseBuilder.notDestroyed(messageId, + SetError.builder() + .type("anErrorOccurred") + .description("An error occurred while deleting message " + messageId.serialize()) + .build()); + } + }; + } + + private MailboxMessage<Id> getMailboxMessage(MessageMapper<Id> messageMapper, MessageId messageId, Mailbox<Id> mailbox) + throws MailboxException, MessageNotFoundException { + + Iterator<MailboxMessage<Id>> mailboxMessage = messageMapper.findInMailbox(mailbox, MessageRange.one(messageId.getUid()), FetchType.Metadata, LIMIT_BY_ONE); + if (!mailboxMessage.hasNext()) { + throw new MessageNotFoundException(); + } + return mailboxMessage.next(); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageId.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageId.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageId.java index 6597111..b4b08c5 100644 --- a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageId.java +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/MessageId.java @@ -22,6 +22,7 @@ import java.util.Objects; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.MailboxSession.User; +import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.mailbox.model.MailboxPath; import org.javatuples.Triplet; @@ -67,7 +68,7 @@ public class MessageId { } public MailboxPath getMailboxPath(MailboxSession mailboxSession) { - return new MailboxPath("", username, mailboxPath); + return new MailboxPath(MailboxConstants.USER_NAMESPACE, username, mailboxPath); } @JsonValue http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java new file mode 100644 index 0000000..da94af5 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetError.java @@ -0,0 +1,80 @@ +/**************************************************************** + * 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.jmap.model; + +import java.util.Optional; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.base.Preconditions; +import com.google.common.base.Strings; + +@JsonDeserialize(builder = SetError.Builder.class) +public class SetError { + + public static Builder builder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + + private String type; + private String description; + + private Builder() { + } + + public Builder type(String type) { + this.type = type; + return this; + } + + public Builder description(String description) { + this.description = description; + return this; + } + + public SetError build() { + Preconditions.checkState(!Strings.isNullOrEmpty(type), "'type' is mandatory"); + return new SetError(type, Optional.ofNullable(description)); + } + } + + private final String type; + private final Optional<String> description; + + @VisibleForTesting SetError(String type, Optional<String> description) { + this.type = type; + this.description = description; + } + + @JsonSerialize + public String getType() { + return type; + } + + @JsonSerialize + public Optional<String> getDescription() { + return description; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesRequest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesRequest.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesRequest.java new file mode 100644 index 0000000..9d6d158 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesRequest.java @@ -0,0 +1,126 @@ +/**************************************************************** + * 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.jmap.model; + +import java.util.List; +import java.util.Optional; + +import org.apache.commons.lang.NotImplementedException; +import org.apache.james.jmap.methods.JmapRequest; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; + +@JsonDeserialize(builder = SetMessagesRequest.Builder.class) +public class SetMessagesRequest implements JmapRequest { + + public static Builder builder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + + private String accountId; + private String ifInState; + private ImmutableList.Builder<Message> create; + private ImmutableList.Builder<Message> update; + private ImmutableList.Builder<MessageId> destroy; + + private Builder() { + create = ImmutableList.builder(); + update = ImmutableList.builder(); + destroy = ImmutableList.builder(); + } + + public Builder accountId(String accountId) { + if (accountId != null) { + throw new NotImplementedException(); + } + return this; + } + + public Builder ifInState(String ifInState) { + if (ifInState != null) { + throw new NotImplementedException(); + } + return this; + } + + public Builder create(List<Message> create) { + if (create != null && !create.isEmpty()) { + throw new NotImplementedException(); + } + return this; + } + + public Builder update(List<Message> update) { + if (update != null && !update.isEmpty()) { + throw new NotImplementedException(); + } + return this; + } + + public Builder destroy(List<MessageId> destroy) { + this.destroy.addAll(destroy); + return this; + } + + public SetMessagesRequest build() { + return new SetMessagesRequest(Optional.ofNullable(accountId), Optional.ofNullable(ifInState), create.build(), update.build(), destroy.build()); + } + } + + private final Optional<String> accountId; + private final Optional<String> ifInState; + private final List<Message> create; + private final List<Message> update; + private final List<MessageId> destroy; + + @VisibleForTesting SetMessagesRequest(Optional<String> accountId, Optional<String> ifInState, List<Message> create, List<Message> update, List<MessageId> destroy) { + this.accountId = accountId; + this.ifInState = ifInState; + this.create = create; + this.update = update; + this.destroy = destroy; + } + + public Optional<String> getAccountId() { + return accountId; + } + + public Optional<String> getIfInState() { + return ifInState; + } + + public List<Message> getCreate() { + return create; + } + + public List<Message> getUpdate() { + return update; + } + + public List<MessageId> getDestroy() { + return destroy; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesResponse.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesResponse.java b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesResponse.java new file mode 100644 index 0000000..67bdd46 --- /dev/null +++ b/server/protocols/jmap/src/main/java/org/apache/james/jmap/model/SetMessagesResponse.java @@ -0,0 +1,188 @@ +/**************************************************************** + * 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.jmap.model; + +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang.NotImplementedException; +import org.apache.james.jmap.methods.Method; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +@JsonDeserialize(builder = SetMessagesResponse.Builder.class) +public class SetMessagesResponse implements Method.Response { + + public static Builder builder() { + return new Builder(); + } + + @JsonPOJOBuilder(withPrefix = "") + public static class Builder { + + private String accountId; + private String oldState; + private String newState; + private ImmutableList.Builder<Message> created; + private ImmutableList.Builder<MessageId> updated; + private ImmutableList.Builder<MessageId> destroyed; + private ImmutableMap.Builder<MessageId, SetError> notCreated; + private ImmutableMap.Builder<MessageId, SetError> notUpdated; + private ImmutableMap.Builder<MessageId, SetError> notDestroyed; + + private Builder() { + created = ImmutableList.builder(); + updated = ImmutableList.builder(); + destroyed = ImmutableList.builder(); + notCreated = ImmutableMap.builder(); + notUpdated = ImmutableMap.builder(); + notDestroyed = ImmutableMap.builder(); + } + + public Builder accountId(String accountId) { + throw new NotImplementedException(); + } + + public Builder oldState(String oldState) { + throw new NotImplementedException(); + } + + public Builder newState(String newState) { + throw new NotImplementedException(); + } + + public Builder created(List<Message> created) { + this.created.addAll(created); + return this; + } + + public Builder updated(List<MessageId> updated) { + this.updated.addAll(updated); + return this; + } + + public Builder destroyed(MessageId destroyed) { + this.destroyed.add(destroyed); + return this; + } + + public Builder destroyed(List<MessageId> destroyed) { + this.destroyed.addAll(destroyed); + return this; + } + + public Builder notCreated(Map<MessageId, SetError> notCreated) { + this.notCreated.putAll(notCreated); + return this; + } + + public Builder notUpdated(Map<MessageId, SetError> notUpdated) { + this.notUpdated.putAll(notUpdated); + return this; + } + + public Builder notDestroyed(MessageId messageId, SetError notDestroyed) { + this.notDestroyed.put(messageId, notDestroyed); + return this; + } + + public Builder notDestroyed(Map<MessageId, SetError> notDestroyed) { + this.notDestroyed.putAll(notDestroyed); + return this; + } + + public SetMessagesResponse build() { + return new SetMessagesResponse(accountId, oldState, newState, + created.build(), updated.build(), destroyed.build(), notCreated.build(), notUpdated.build(), notDestroyed.build()); + } + } + + private final String accountId; + private final String oldState; + private final String newState; + private final List<Message> created; + private final List<MessageId> updated; + private final List<MessageId> destroyed; + private final Map<MessageId, SetError> notCreated; + private final Map<MessageId, SetError> notUpdated; + private final Map<MessageId, SetError> notDestroyed; + + @VisibleForTesting SetMessagesResponse(String accountId, String oldState, String newState, List<Message> created, List<MessageId> updated, List<MessageId> destroyed, + Map<MessageId, SetError> notCreated, Map<MessageId, SetError> notUpdated, Map<MessageId, SetError> notDestroyed) { + this.accountId = accountId; + this.oldState = oldState; + this.newState = newState; + this.created = created; + this.updated = updated; + this.destroyed = destroyed; + this.notCreated = notCreated; + this.notUpdated = notUpdated; + this.notDestroyed = notDestroyed; + } + + @JsonSerialize + public String getAccountId() { + return accountId; + } + + @JsonSerialize + public String getOldState() { + return oldState; + } + + @JsonSerialize + public String getNewState() { + return newState; + } + + @JsonSerialize + public List<Message> getCreated() { + return created; + } + + @JsonSerialize + public List<MessageId> getUpdated() { + return updated; + } + + @JsonSerialize + public List<MessageId> getDestroyed() { + return destroyed; + } + + @JsonSerialize + public Map<MessageId, SetError> getNotCreated() { + return notCreated; + } + + @JsonSerialize + public Map<MessageId, SetError> getNotUpdated() { + return notUpdated; + } + + @JsonSerialize + public Map<MessageId, SetError> getNotDestroyed() { + return notDestroyed; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetErrorTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetErrorTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetErrorTest.java new file mode 100644 index 0000000..1d5ace1 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetErrorTest.java @@ -0,0 +1,59 @@ +/**************************************************************** + * 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.jmap.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.util.Optional; + +import org.junit.Test; + +public class SetErrorTest { + + @Test + public void buildShouldThrowWhenTypeIsNotGiven() { + assertThatThrownBy(() -> SetError.builder().build()) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void buildShouldWorkWhenAllMandatoryFieldsAreGiven() { + SetError expected = new SetError("type", Optional.empty()); + + SetError setError = SetError.builder() + .type("type") + .build(); + + assertThat(setError).isEqualToComparingFieldByField(expected); + } + + @Test + public void buildShouldWorkWhenAllFieldsAreGiven() { + SetError expected = new SetError("type", Optional.of("description")); + + SetError setError = SetError.builder() + .type("type") + .description("description") + .build(); + + assertThat(setError).isEqualToComparingFieldByField(expected); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesRequestTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesRequestTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesRequestTest.java new file mode 100644 index 0000000..b600172 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesRequestTest.java @@ -0,0 +1,96 @@ +/**************************************************************** + * 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.jmap.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.ZonedDateTime; +import java.util.Optional; + +import org.apache.commons.lang.NotImplementedException; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class SetMessagesRequestTest { + + @Test + public void builderShouldThrowWhenAccountIdIsNotNull() { + assertThatThrownBy(() -> SetMessagesRequest.builder().accountId("")) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldThrowWhenIfInStateIsNotNull() { + assertThatThrownBy(() -> SetMessagesRequest.builder().ifInState("")) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldThrowWhenCreateIsNotEmpty() { + assertThatThrownBy(() -> SetMessagesRequest.builder().create(ImmutableList.of(Message.builder() + .id(MessageId.of("user|create|1")) + .blobId("blobId") + .threadId("threadId") + .mailboxIds(ImmutableList.of("mailboxId")) + .headers(ImmutableMap.of("key", "value")) + .subject("subject") + .size(123) + .date(ZonedDateTime.now()) + .preview("preview") + .build()))) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldThrowWhenUpdateIsNotEmpty() { + assertThatThrownBy(() -> SetMessagesRequest.builder().update(ImmutableList.of(Message.builder() + .id(MessageId.of("user|create|1")) + .blobId("blobId") + .threadId("threadId") + .mailboxIds(ImmutableList.of("mailboxId")) + .headers(ImmutableMap.of("key", "value")) + .subject("subject") + .size(123) + .date(ZonedDateTime.now()) + .preview("preview") + .build()))) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldWork() { + ImmutableList<MessageId> destroy = ImmutableList.of(MessageId.of("user|destroy|1")); + + SetMessagesRequest expected = new SetMessagesRequest(Optional.empty(), Optional.empty(), ImmutableList.of(), ImmutableList.of(), destroy); + + SetMessagesRequest setMessagesRequest = SetMessagesRequest.builder() + .accountId(null) + .ifInState(null) + .create(ImmutableList.of()) + .update(ImmutableList.of()) + .destroy(destroy) + .build(); + + assertThat(setMessagesRequest).isEqualToComparingFieldByField(expected); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/6665a49e/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesResponseTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesResponseTest.java b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesResponseTest.java new file mode 100644 index 0000000..23743f3 --- /dev/null +++ b/server/protocols/jmap/src/test/java/org/apache/james/jmap/model/SetMessagesResponseTest.java @@ -0,0 +1,86 @@ +/**************************************************************** + * 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.jmap.model; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import java.time.ZonedDateTime; + +import org.apache.commons.lang.NotImplementedException; +import org.junit.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class SetMessagesResponseTest { + + @Test + public void builderShouldThrowWhenAccountIdIsGiven() { + assertThatThrownBy(() -> SetMessagesResponse.builder().accountId("")) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldThrowWhenOldStateGiven() { + assertThatThrownBy(() -> SetMessagesResponse.builder().oldState("")) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldThrowWhenNewStateIsGiven() { + assertThatThrownBy(() -> SetMessagesResponse.builder().newState("")) + .isInstanceOf(NotImplementedException.class); + } + + @Test + public void builderShouldWork() { + ZonedDateTime currentDate = ZonedDateTime.now(); + ImmutableList<Message> created = ImmutableList.of( + Message.builder() + .id(MessageId.of("user|created|1")) + .blobId("blobId") + .threadId("threadId") + .mailboxIds(ImmutableList.of("mailboxId")) + .headers(ImmutableMap.of("key", "value")) + .subject("subject") + .size(123) + .date(currentDate) + .preview("preview") + .build()); + ImmutableList<MessageId> updated = ImmutableList.of(MessageId.of("user|updated|1")); + ImmutableList<MessageId> destroyed = ImmutableList.of(MessageId.of("user|destroyed|1")); + ImmutableMap<MessageId, SetError> notCreated = ImmutableMap.of(MessageId.of("user|created|2"), SetError.builder().type("created").build()); + ImmutableMap<MessageId, SetError> notUpdated = ImmutableMap.of(MessageId.of("user|update|2"), SetError.builder().type("updated").build()); + ImmutableMap<MessageId, SetError> notDestroyed = ImmutableMap.of(MessageId.of("user|destroyed|3"), SetError.builder().type("destroyed").build()); + SetMessagesResponse expected = new SetMessagesResponse(null, null, null, created, updated, destroyed, notCreated, notUpdated, notDestroyed); + + SetMessagesResponse setMessagesResponse = SetMessagesResponse.builder() + .created(created) + .updated(updated) + .destroyed(destroyed) + .notCreated(notCreated) + .notUpdated(notUpdated) + .notDestroyed(notDestroyed) + .build(); + + assertThat(setMessagesResponse).isEqualToComparingFieldByField(expected); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
