JAMES-1717 Integration tests other JMAP for the vacation answer capability
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/03a46df8 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/03a46df8 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/03a46df8 Branch: refs/heads/master Commit: 03a46df84f2560a5549e22e9d0ad08647810adde Parents: 57ad3d4 Author: Benoit Tellier <[email protected]> Authored: Tue Apr 26 17:56:51 2016 +0700 Committer: Benoit Tellier <[email protected]> Committed: Fri May 20 18:52:11 2016 +0700 ---------------------------------------------------------------------- .../CassandraVacationIntegrationTest.java | 55 ++++ .../james/jmap/VacationIntegrationTest.java | 283 +++++++++++++++++++ .../memory/MemoryVacationIntegrationTest.java | 43 +++ 3 files changed, 381 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/03a46df8/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/src/test/java/org/apache/james/jmap/cassandra/CassandraVacationIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/src/test/java/org/apache/james/jmap/cassandra/CassandraVacationIntegrationTest.java b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/src/test/java/org/apache/james/jmap/cassandra/CassandraVacationIntegrationTest.java new file mode 100644 index 0000000..b5a383d --- /dev/null +++ b/server/protocols/jmap-integration-testing/cassandra-jmap-integration-testing/src/test/java/org/apache/james/jmap/cassandra/CassandraVacationIntegrationTest.java @@ -0,0 +1,55 @@ +/**************************************************************** + * 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.cassandra; + +import org.apache.james.CassandraJamesServerMain; +import org.apache.james.GuiceJamesServer; +import org.apache.james.backends.cassandra.EmbeddedCassandra; +import org.apache.james.jmap.VacationIntegrationTest; +import org.apache.james.mailbox.elasticsearch.EmbeddedElasticSearch; +import org.apache.james.modules.CassandraJmapServerModule; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.rules.TemporaryFolder; + +public class CassandraVacationIntegrationTest extends VacationIntegrationTest { + + + private TemporaryFolder temporaryFolder = new TemporaryFolder(); + private EmbeddedElasticSearch embeddedElasticSearch = new EmbeddedElasticSearch(temporaryFolder); + private EmbeddedCassandra cassandra = EmbeddedCassandra.createStartServer(); + + @Rule + public RuleChain chain = RuleChain + .outerRule(temporaryFolder) + .around(embeddedElasticSearch); + + @Override + protected GuiceJamesServer createJmapServer() { + return new GuiceJamesServer() + .combineWith(CassandraJamesServerMain.cassandraServerModule) + .overrideWith(new CassandraJmapServerModule(temporaryFolder, embeddedElasticSearch, cassandra)); + } + + @Override + protected void await() { + embeddedElasticSearch.awaitForElasticSearch(); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/03a46df8/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java new file mode 100644 index 0000000..c2672bc --- /dev/null +++ b/server/protocols/jmap-integration-testing/jmap-integration-testing-common/src/test/java/org/apache/james/jmap/VacationIntegrationTest.java @@ -0,0 +1,283 @@ +/**************************************************************** + * 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; + +import static com.jayway.restassured.RestAssured.given; +import static com.jayway.restassured.RestAssured.with; +import static com.jayway.restassured.config.EncoderConfig.encoderConfig; +import static com.jayway.restassured.config.RestAssuredConfig.newConfig; +import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.james.GuiceJamesServer; +import org.apache.james.jmap.api.access.AccessToken; +import org.apache.james.mailbox.model.MailboxConstants; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import com.google.common.base.Charsets; +import com.jayway.awaitility.Awaitility; +import com.jayway.awaitility.Duration; +import com.jayway.awaitility.core.ConditionFactory; +import com.jayway.restassured.RestAssured; +import com.jayway.restassured.http.ContentType; + +public abstract class VacationIntegrationTest { + + private static final String ARGUMENTS = "[0][1]"; + private static final String SECOND_NAME = "[1][0]"; + private static final String SECOND_ARGUMENTS = "[1][1]"; + private static final String DOMAIN = "mydomain.tld"; + private static final String USER_1 = "benwa@" + DOMAIN; + private static final String USER_2 = "matthieu@" + DOMAIN; + private static final String PASSWORD = "secret"; + private static final String REASON = "Message explaining my wonderful vacations"; + + private ConditionFactory calmlyAwait; + private GuiceJamesServer guiceJamesServer; + + protected abstract GuiceJamesServer createJmapServer(); + + protected abstract void await(); + + @Before + public void setUp() throws Exception { + guiceJamesServer = createJmapServer(); + guiceJamesServer.start(); + + guiceJamesServer.serverProbe().addDomain(DOMAIN); + guiceJamesServer.serverProbe().addUser(USER_1, PASSWORD); + guiceJamesServer.serverProbe().addUser(USER_2, PASSWORD); + guiceJamesServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, USER_2, "outbox"); + guiceJamesServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, USER_1, "sent"); + guiceJamesServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, USER_2, "sent"); + await(); + + + RestAssured.port = guiceJamesServer.getJmapPort(); + RestAssured.config = newConfig().encoderConfig(encoderConfig().defaultContentCharset(Charsets.UTF_8)); + + Duration slowPacedPollInterval = Duration.FIVE_HUNDRED_MILLISECONDS; + calmlyAwait = Awaitility.with().pollInterval(slowPacedPollInterval).and().with().pollDelay(slowPacedPollInterval).await(); + } + + @After + public void teardown() { + guiceJamesServer.stop(); + } + + @Test + public void jmapVacationShouldGenerateAReplyWhenActive() throws Exception { + /* Test scenario : + - User 1 [email protected] sets a Vacation on its account + - User 2 [email protected] sends User 1 a mail + - User 1 should well receive this mail + - User 2 should well receive a notification about user 1 vacation + */ + + // Given + AccessToken user1AccessToken = JmapAuthentication.authenticateJamesUser(USER_1, PASSWORD); + AccessToken user2AccessToken = JmapAuthentication.authenticateJamesUser(USER_2, PASSWORD); + // User 1 [email protected] sets a Vacation on its account + String bodyRequest = "[[" + + "\"setVacationResponse\", " + + "{" + + " \"update\":{" + + " \"singleton\" : {" + + " \"id\": \"singleton\"," + + " \"isEnabled\": \"true\"," + + " \"textBody\": \"" + REASON + "\"" + + " }" + + " }" + + "}, \"#0\"" + + "]]"; + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", user1AccessToken.serialize()) + .body(bodyRequest) + .when() + .post("/jmap") + .then() + .statusCode(200); + + // When + // User 2 [email protected] sends User 1 a mail + String originalMessageTextBody = "Hello someone, and thank you for joining example.com!"; + String requestBody = "[" + + " [" + + " \"setMessages\","+ + " {" + + " \"create\": { \"user|inbox|1\" : {" + + " \"from\": { \"email\": \"" + USER_2 + "\"}," + + " \"to\": [{ \"name\": \"Benwa\", \"email\": \"" + USER_1 + "\"}]," + + " \"subject\": \"Thank you for joining example.com!\"," + + " \"textBody\": \"" + originalMessageTextBody + "\"," + + " \"mailboxIds\": [\"" + getOutboxId(user2AccessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", user2AccessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap"); + + // Then + // User 1 should well receive this mail + calmlyAwait.atMost(10, TimeUnit.SECONDS) + .until( () -> isTextMessageReceived(user1AccessToken, getInboxId(user1AccessToken), originalMessageTextBody, USER_2, USER_1)); + // User 2 should well receive a notification about user 1 vacation + calmlyAwait.atMost(10, TimeUnit.SECONDS) + .until( () -> isTextMessageReceived(user2AccessToken, getInboxId(user2AccessToken), REASON, USER_1, USER_2)); + } + + @Test + public void jmapVacationShouldNotGenerateAReplyWhenInactive() throws Exception { + /* Test scenario : + - User 2 [email protected] sends User 1 a mail + - User 1 should well receive this mail + - User 2 should not receive a notification + */ + + // Given + guiceJamesServer.serverProbe().createMailbox(MailboxConstants.USER_NAMESPACE, USER_2, "INBOX"); + AccessToken user1AccessToken = JmapAuthentication.authenticateJamesUser(USER_1, PASSWORD); + AccessToken user2AccessToken = JmapAuthentication.authenticateJamesUser(USER_2, PASSWORD); + + // When + // User 2 [email protected] sends User 1 a mail + String originalMessageTextBody = "Hello someone, and thank you for joining example.com!"; + String requestBody = "[" + + " [" + + " \"setMessages\"," + + " {" + + " \"create\": { \"user|inbox|1\" : {" + + " \"from\": { \"email\": \"" + USER_2 + "\"}," + + " \"to\": [{ \"name\": \"Benwa\", \"email\": \"" + USER_1 + "\"}]," + + " \"subject\": \"Thank you for joining example.com!\"," + + " \"textBody\": \"" + originalMessageTextBody + "\"," + + " \"mailboxIds\": [\"" + getOutboxId(user2AccessToken) + "\"]" + + " }}" + + " }," + + " \"#0\"" + + " ]" + + "]"; + given() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", user2AccessToken.serialize()) + .body(requestBody) + .when() + .post("/jmap"); + + // Then + // User 1 should well receive this mail + calmlyAwait.atMost(10, TimeUnit.SECONDS) + .until(() -> isTextMessageReceived(user1AccessToken, getInboxId(user1AccessToken), originalMessageTextBody, USER_2, USER_1)); + // User 2 should not receive a notification + Thread.sleep(1000L); + with() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", user2AccessToken.serialize()) + .body("[[\"getMessageList\", " + + "{" + + " \"fetchMessages\": true, " + + " \"filter\": {" + + " \"inMailboxes\":[\"" + getInboxId(user2AccessToken) + "\"]" + + " }" + + "}, \"#0\"]]") + .post("/jmap") + .then() + .statusCode(200) + .body(SECOND_NAME, equalTo("messages")) + .body(SECOND_ARGUMENTS + ".list", empty()); + } + + private boolean isTextMessageReceived(AccessToken recipientToken, String mailboxId, String expectedTextBody, String expectedFrom, String expectedTo) { + try { + with() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", recipientToken.serialize()) + .body("[[\"getMessageList\", " + + "{" + + " \"fetchMessages\": true, " + + " \"fetchMessageProperties\": [\"textBody\", \"from\", \"to\", \"mailboxIds\"]," + + " \"filter\": {" + + " \"inMailboxes\":[\"" + mailboxId + "\"]" + + " }" + + "}, \"#0\"]]") + .post("/jmap") + .then() + .statusCode(200) + .body(SECOND_NAME, equalTo("messages")) + .body(SECOND_ARGUMENTS + ".list", hasSize(1)) + .body(SECOND_ARGUMENTS + ".list[0].textBody", equalTo(expectedTextBody)) + .body(SECOND_ARGUMENTS + ".list[0].from.email", equalTo(expectedFrom)) + .body(SECOND_ARGUMENTS + ".list[0].to.email", hasSize(1)) + .body(SECOND_ARGUMENTS + ".list[0].to.email[0]", equalTo(expectedTo)); + return true; + } catch(AssertionError e) { + return false; + } + } + + private String getOutboxId(AccessToken accessToken) { + return getMailboxIdByRole(accessToken, "outbox"); + } + + private String getInboxId(AccessToken accessToken) { + return getMailboxIdByRole(accessToken, "inbox"); + } + + private String getMailboxIdByRole(AccessToken accessToken, String role) { + return getAllMailboxesIds(accessToken).stream() + .filter(x -> x.get("role").equals(role)) + .map(x -> x.get("id")) + .findFirst() + .get(); + } + + private List<Map<String, String>> getAllMailboxesIds(AccessToken accessToken) { + return with() + .accept(ContentType.JSON) + .contentType(ContentType.JSON) + .header("Authorization", accessToken.serialize()) + .body("[[\"getMailboxes\", {\"properties\": [\"role\", \"id\"]}, \"#0\"]]") + .post("/jmap") + .andReturn() + .body() + .jsonPath() + .getList(ARGUMENTS + ".list"); + } + +} http://git-wip-us.apache.org/repos/asf/james-project/blob/03a46df8/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryVacationIntegrationTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryVacationIntegrationTest.java b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryVacationIntegrationTest.java new file mode 100644 index 0000000..de4eb41 --- /dev/null +++ b/server/protocols/jmap-integration-testing/memory-jmap-integration-testing/src/test/java/org/apache/james/jmap/memory/MemoryVacationIntegrationTest.java @@ -0,0 +1,43 @@ +/**************************************************************** + * 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.memory; + +import org.apache.james.GuiceJamesServer; +import org.apache.james.MemoryJamesServerMain; +import org.apache.james.jmap.VacationIntegrationTest; +import org.apache.james.jmap.servers.MemoryJmapServerModule; +import org.junit.Rule; +import org.junit.rules.TemporaryFolder; + +public class MemoryVacationIntegrationTest extends VacationIntegrationTest { + + @Rule + public TemporaryFolder temporaryFolder = new TemporaryFolder(); + + @Override + protected GuiceJamesServer createJmapServer() { + return new GuiceJamesServer() + .combineWith(MemoryJamesServerMain.inMemoryServerModule) + .overrideWith(new MemoryJmapServerModule(temporaryFolder)); + } + + @Override + protected void await() {} +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
