This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit bc345c32ec8653784074f16834f56bcd4641027e Author: vttran <[email protected]> AuthorDate: Tue Apr 9 18:21:26 2024 +0700 JAMES-4025 Rewrite some tests of JMAP draft on top of JMAP RFC-8621 (module: spamassassin) --- .../james/spamassassin/SpamAssassinContract.java | 738 +++++++++------------ .../module/SpamAssassinTestModule.java | 8 +- 2 files changed, 330 insertions(+), 416 deletions(-) diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinContract.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinContract.java index 35fb7522bb..284698093d 100644 --- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinContract.java +++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/SpamAssassinContract.java @@ -24,32 +24,30 @@ import static io.restassured.RestAssured.given; import static io.restassured.RestAssured.with; import static io.restassured.config.EncoderConfig.encoderConfig; import static io.restassured.config.RestAssuredConfig.newConfig; -import static org.apache.james.jmap.HttpJmapAuthentication.authenticateJamesUser; -import static org.apache.james.jmap.JMAPTestingConstants.ARGUMENTS; +import static io.restassured.http.ContentType.JSON; import static org.apache.james.jmap.JMAPTestingConstants.LOCALHOST_IP; -import static org.apache.james.jmap.JMAPTestingConstants.NAME; import static org.apache.james.jmap.JMAPTestingConstants.calmlyAwait; +import static org.apache.james.jmap.JmapRFCCommonRequests.ACCEPT_JMAP_RFC_HEADER; +import static org.apache.james.jmap.JmapRFCCommonRequests.UserCredential; +import static org.apache.james.jmap.JmapRFCCommonRequests.getMailboxId; +import static org.apache.james.jmap.JmapRFCCommonRequests.getUserCredential; import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Durations.ONE_MINUTE; -import static org.hamcrest.Matchers.equalTo; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.notNullValue; import java.nio.charset.StandardCharsets; import java.util.List; -import java.util.Map; +import java.util.function.Consumer; -import org.apache.http.client.utils.URIBuilder; import org.apache.james.GuiceJamesServer; -import org.apache.james.core.Username; -import org.apache.james.jmap.AccessToken; -import org.apache.james.jmap.LocalHostURIBuilder; +import org.apache.james.jmap.JmapRFCCommonRequests; import org.apache.james.jmap.draft.JmapGuiceProbe; import org.apache.james.mailbox.Role; import org.apache.james.modules.protocols.ImapGuiceProbe; -import org.apache.james.util.Port; import org.apache.james.utils.DataProbeImpl; import org.apache.james.utils.SpoolerProbe; import org.apache.james.utils.TestIMAPClient; +import org.hamcrest.Matchers; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -77,6 +75,7 @@ public interface SpamAssassinContract { .setAccept(ContentType.JSON) .setConfig(newConfig().encoderConfig(encoderConfig().defaultContentCharset(StandardCharsets.UTF_8))) .setPort(jamesServer.getProbe(JmapGuiceProbe.class).getJmapPort().getValue()) + .addHeader(ACCEPT_JMAP_RFC_HEADER.getName(), ACCEPT_JMAP_RFC_HEADER.getValue()) .build(); RestAssured.defaultParser = Parser.JSON; @@ -95,79 +94,71 @@ public interface SpamAssassinContract { spamAssassin.clear(ALICE); } - default AccessToken accessTokenFor(GuiceJamesServer james, String user, String password) { - return authenticateJamesUser(baseUri(james), Username.of(user), password); - } - @Test default void spamShouldBeDeliveredInSpamMailboxWhenSameMessageHasAlreadyBeenMovedToSpam( GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") + String aliceInboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX); + List<String> msgIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, aliceInboxId); + + String aliceSpamMailboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.SPAM); + + Consumer<String> moveMessageToSpamMailbox = messageId -> given() + .auth().basic(aliceCredential.username().asString(), aliceCredential.password()) + .body(""" + { + "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], + "methodCalls": [ + ["Email/set", { + "accountId": "%s", + "update": { + "%s":{ + "mailboxIds": { "%s" : true} + } + } + }, "c1"]] + }""".formatted(aliceCredential.accountId(), messageId, aliceSpamMailboxId)) .when() .post("/jmap") .then() .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + .contentType(JSON); + + msgIds.forEach(moveMessageToSpamMailbox); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice Spam mailbox (she now must have 2 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 2)); } @Test default void imapCopiesToSpamMailboxShouldBeConsideredAsSpam(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); @@ -179,33 +170,25 @@ public interface SpamAssassinContract { testIMAPClient.copyFirstMessage("Spam"); } - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice Spam mailbox (she now must have 2 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 2)); } @Test default void imapMovesToSpamMailboxShouldBeConsideredAsSpam(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); try (TestIMAPClient testIMAPClient = new TestIMAPClient()) { @@ -215,189 +198,141 @@ public interface SpamAssassinContract { testIMAPClient.moveFirstMessage("Spam"); } - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice Spam mailbox (she now must have 2 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 2)); } @Test default void spamAssassinShouldForgetMessagesMovedOutOfSpamFolderUsingJMAP(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") + String aliceInboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX); + List<String> msgIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, aliceInboxId); + + String aliceSpamMailboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.SPAM); + + Consumer<String> moveMessageToSpamMailbox = messageId -> given() + .auth().basic(aliceCredential.username().asString(), aliceCredential.password()) + .body(""" + { + "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], + "methodCalls": [ + ["Email/set", { + "accountId": "%s", + "update": { + "%s":{ + "mailboxIds": { "%s" : true} + } + } + }, "c1"]] + }""".formatted(aliceCredential.accountId(), messageId, aliceSpamMailboxId)) .when() .post("/jmap") .then() .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + .contentType(JSON); + + msgIds.forEach(moveMessageToSpamMailbox); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Alice is moving this message out of Spam -> forgetting in SpamAssassin - messageIds - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getInboxId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + Consumer<String> moveMessageOutOfSpamMailbox = messageId -> given() + .auth().basic(aliceCredential.username().asString(), aliceCredential.password()) + .body(""" + { + "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], + "methodCalls": [ + ["Email/set", { + "accountId": "%s", + "update": { + "%s":{ + "mailboxIds": { "%s" : true} + } + } + }, "c1"]] + }""".formatted(aliceCredential.accountId(), messageId, aliceInboxId)) + .when() + .post("/jmap") + .then() + .statusCode(200) + .contentType(JSON); + msgIds.forEach(moveMessageOutOfSpamMailbox); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice INBOX mailbox (she now must have 2 messages in her Inbox mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 2)); } @Test default void movingAMailToTrashShouldNotImpactSpamassassinLearning(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + String aliceInboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX); + List<String> msgIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, aliceInboxId); + + String aliceSpamMailboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.SPAM); + moveMessagesToNewMailbox(msgIds, aliceSpamMailboxId, aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Alice is moving this message to trash - messageIds - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getTrashId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getTrashId(aliceAccessToken), 1)); + moveMessagesToNewMailbox(msgIds, getTrashId(aliceCredential), aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getTrashId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice Spam mailbox (she now must have 1 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); } @Test default void spamAssassinShouldForgetMessagesMovedOutOfSpamFolderUsingIMAP(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + List<String> messageIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX)); + moveMessagesToNewMailbox(messageIds, getMailboxId(aliceCredential, Role.SPAM), aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Alice is moving this message out of Spam -> forgetting in SpamAssassin try (TestIMAPClient testIMAPClient = new TestIMAPClient()) { @@ -407,59 +342,32 @@ public interface SpamAssassinContract { testIMAPClient.moveFirstMessage(TestIMAPClient.INBOX); } - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice INBOX mailbox (she now must have 2 messages in her Inbox mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 2)); } @Test default void expungingSpamMessageShouldNotImpactSpamAssassinState(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + List<String> messageIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX)); + moveMessagesToNewMailbox(messageIds, getMailboxId(aliceCredential, Role.SPAM), aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Alice is deleting this message try (TestIMAPClient testIMAPClient = new TestIMAPClient()) { @@ -470,222 +378,210 @@ public interface SpamAssassinContract { testIMAPClient.setFlagsForAllMessagesInMailbox("\\Deleted"); testIMAPClient.expunge(); } - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 0)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 0)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice SPAM mailbox (she now must have 1 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); } @Test default void deletingSpamMessageShouldNotImpactSpamAssassinState(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); // Bob is sending a message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); + bobSendSpamEmailToAlice(bobCredential); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertEveryListenerGotCalled(jamesServer)); // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + List<String> messageIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX)); + moveMessagesToNewMailbox(messageIds, getMailboxId(aliceCredential, Role.SPAM), aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Alice is deleting this message - messageIds - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"destroy\": [\"%s\"] }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".destroyed", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 0)); + JmapRFCCommonRequests.deleteMessages(aliceCredential, messageIds); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 0)); // Bob is sending again the same message to Alice - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreate(bobAccessToken)) - .when() - .post("/jmap"); + bobSendSpamEmailToAlice(bobCredential); // This message is delivered in Alice SPAM mailbox (she now must have 1 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); } - default String setMessageCreate(AccessToken accessToken) { - return "[" + - " [" + - " \"setMessages\"," + - " {" + - " \"create\": { \"creationId1337\" : {" + - " \"from\": { \"email\": \"" + BOB + "\"}," + - " \"to\": [{ \"name\": \"recipient\", \"email\": \"" + ALICE + "\"}]," + - " \"subject\": \"Happy News\"," + - " \"textBody\": \"This is a SPAM!!!\r\n\r\n\"," + - " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + - " }}" + - " }," + - " \"#0\"" + - " ]" + - "]"; + default void bobSendSpamEmailToAlice(UserCredential bobCredential) { + String bobOutboxId = JmapRFCCommonRequests.getOutboxId(bobCredential); + String requestBody = + "{" + + " \"using\": [\"urn:ietf:params:jmap:core\", \"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," + + " \"methodCalls\": [" + + " [\"Email/set\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"create\": {" + + " \"e1526\": {" + + " \"mailboxIds\": { \"" + bobOutboxId + "\": true }," + + " \"subject\": \"Happy News\"," + + " \"textBody\": [{" + + " \"partId\": \"a49d\"," + + " \"type\": \"text/plain\"" + + " }]," + + " \"bodyValues\": {" + + " \"a49d\": {" + + " \"value\": \"This is a SPAM!!!\"" + + " }" + + " }," + + " \"to\": [{" + + " \"email\": \"" + ALICE + "\"" + + " }]," + + " \"from\": [{" + + " \"email\": \"" + BOB + "\"" + + " }]" + + " }" + + " }" + + " }, \"c1\"]," + + " [\"Email/get\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"ids\": [\"#e1526\"]," + + " \"properties\": [\"sentAt\"]" + + " }, \"c2\"]," + + " [\"EmailSubmission/set\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"create\": {" + + " \"k1490\": {" + + " \"emailId\": \"#e1526\"," + + " \"envelope\": {" + + " \"mailFrom\": {\"email\": \"" + BOB + "\"}," + + " \"rcptTo\": [{" + + " \"email\": \"" + ALICE + "\"" + + " }]" + + " }" + + " }" + + " }" + + " }, \"c3\"]" + + " ]" + + "}"; + + with() + .auth().basic(bobCredential.username().asString(), bobCredential.password()) + .body(requestBody) + .post("/jmap") + .then() + .statusCode(200) + .contentType(JSON) + .body("methodResponses[2][1].created", Matchers.is(notNullValue())); + } @Test default void spamShouldBeDeliveredInSpamMailboxOrInboxWhenMultipleRecipientsConfigurations(GuiceJamesServer jamesServer, SpamAssassinExtension.SpamAssassin spamAssassin) throws Exception { spamAssassin.train(ALICE); - AccessToken aliceAccessToken = accessTokenFor(jamesServer, ALICE, ALICE_PASSWORD); - AccessToken bobAccessToken = accessTokenFor(jamesServer, BOB, BOB_PASSWORD); - AccessToken paulAccessToken = accessTokenFor(jamesServer, PAUL, PAUL_PASSWORD); + UserCredential aliceCredential = getUserCredential(ALICE, ALICE_PASSWORD); + UserCredential bobCredential = getUserCredential(BOB, BOB_PASSWORD); + UserCredential paulCredential = getUserCredential(PAUL, PAUL_PASSWORD); // Bob is sending a message to Alice & Paul - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreateToMultipleRecipients(bobAccessToken)) - .when() - .post("/jmap"); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 1)); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulAccessToken, getInboxId(paulAccessToken), 1)); - - // Alice is moving this message to Spam -> learning in SpamAssassin - List<String> messageIds = with() - .header("Authorization", aliceAccessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + getInboxId(aliceAccessToken) + "\"]}}, \"#0\"]]") - .when() + String bobSendSpamEmailToAliceAndPaulRequest = + "{" + + " \"using\": [\"urn:ietf:params:jmap:core\", \"urn:ietf:params:jmap:mail\", \"urn:ietf:params:jmap:submission\"]," + + " \"methodCalls\": [" + + " [\"Email/set\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"create\": {" + + " \"e1526\": {" + + " \"mailboxIds\": { \"" + JmapRFCCommonRequests.getOutboxId(bobCredential) + "\": true }," + + " \"subject\": \"Happy News\"," + + " \"textBody\": [{" + + " \"partId\": \"a49d\"," + + " \"type\": \"text/plain\"" + + " }]," + + " \"bodyValues\": {" + + " \"a49d\": {" + + " \"value\": \"This is a SPAM!!!\"" + + " }" + + " }," + + " \"to\": [{\"email\": \"" + ALICE + "\"}, {\"email\": \"" + PAUL + "\"}]," + + " \"from\": [{" + + " \"email\": \"" + BOB + "\"" + + " }]" + + " }" + + " }" + + " }, \"c1\"]," + + " [\"Email/get\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"ids\": [\"#e1526\"]," + + " \"properties\": [\"sentAt\"]" + + " }, \"c2\"]," + + " [\"EmailSubmission/set\", {" + + " \"accountId\": \"" + bobCredential.accountId() + "\"," + + " \"create\": {" + + " \"k1490\": {" + + " \"emailId\": \"#e1526\"," + + " \"envelope\": {" + + " \"mailFrom\": {\"email\": \"" + BOB + "\"}," + + " \"rcptTo\": [{\"email\": \"" + ALICE + "\"}, {\"email\": \"" + PAUL + "\"}]" + + " }" + + " }" + + " }" + + " }, \"c3\"]" + + " ]" + + "}"; + + Consumer<String> bobSendAndEmail = requestBody -> with() + .auth().basic(bobCredential.username().asString(), bobCredential.password()) + .body(requestBody) .post("/jmap") .then() .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(1)) - .extract() - .path(ARGUMENTS + ".messageIds"); - - messageIds.parallelStream() - .forEach(messageId -> given() - .header("Authorization", aliceAccessToken.asString()) - .body(String.format("[[\"setMessages\", {\"update\": {\"%s\" : { \"mailboxIds\": [\"" + getSpamId(aliceAccessToken) + "\"] } } }, \"#0\"]]", messageId)) - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messagesSet")) - .body(ARGUMENTS + ".updated", hasSize(1))); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 1)); + .contentType(JSON) + .body("methodResponses[2][1].created", Matchers.is(notNullValue())); + + bobSendAndEmail.accept(bobSendSpamEmailToAliceAndPaulRequest); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 1)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulCredential, getInboxId(paulCredential), 1)); + + // Alice is moving this message to Spam -> learning in SpamAssassin + String aliceInboxId = JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.INBOX); + List<String> msgIds = JmapRFCCommonRequests.listMessageIdsInMailbox(aliceCredential, aliceInboxId); + moveMessagesToNewMailbox(msgIds, JmapRFCCommonRequests.getMailboxId(aliceCredential, Role.SPAM), aliceCredential); + + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 1)); // Bob is sending again the same message to Alice & Paul - given() - .header("Authorization", bobAccessToken.asString()) - .body(setMessageCreateToMultipleRecipients(bobAccessToken)) - .when() - .post("/jmap"); + bobSendAndEmail.accept(bobSendSpamEmailToAliceAndPaulRequest); // This message is delivered in Alice Spam mailbox (she now must have 2 messages in her Spam mailbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getSpamId(aliceAccessToken), 2)); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceAccessToken, getInboxId(aliceAccessToken), 0)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getSpamId(aliceCredential), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(aliceCredential, getInboxId(aliceCredential), 0)); // This message is delivered in Paul Inbox (he now must have 2 messages in his Inbox) - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulAccessToken, getInboxId(paulAccessToken), 2)); - calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulAccessToken, getSpamId(paulAccessToken), 0)); - } - - default String setMessageCreateToMultipleRecipients(AccessToken accessToken) { - return "[" + - " [" + - " \"setMessages\"," + - " {" + - " \"create\": { \"creationId1337\" : {" + - " \"from\": { \"email\": \"" + BOB + "\"}," + - " \"to\": [{ \"name\": \"alice\", \"email\": \"" + ALICE + "\"}, " + - " { \"name\": \"paul\", \"email\": \"" + PAUL + "\"}]," + - " \"subject\": \"Happy News\"," + - " \"textBody\": \"This is a SPAM!!!\r\n\r\n\"," + - " \"mailboxIds\": [\"" + getOutboxId(accessToken) + "\"]" + - " }}" + - " }," + - " \"#0\"" + - " ]" + - "]"; - } - - default void assertMessagesFoundInMailbox(AccessToken accessToken, String mailboxId, int expectedNumberOfMessages) { - with() - .header("Authorization", accessToken.asString()) - .body("[[\"getMessageList\", {\"filter\":{\"inMailboxes\":[\"" + mailboxId + "\"]}}, \"#0\"]]") - .when() - .post("/jmap") - .then() - .statusCode(200) - .body(NAME, equalTo("messageList")) - .body(ARGUMENTS + ".messageIds", hasSize(expectedNumberOfMessages)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulCredential, getInboxId(paulCredential), 2)); + calmlyAwait.atMost(ONE_MINUTE).untilAsserted(() -> assertMessagesFoundInMailbox(paulCredential, getSpamId(paulCredential), 0)); } - default String getMailboxId(AccessToken accessToken, Role role) { - return getAllMailboxesIds(accessToken).stream() - .filter(x -> x.get("role").equalsIgnoreCase(role.serialize())) - .map(x -> x.get("id")) - .findFirst().get(); + default void assertMessagesFoundInMailbox(UserCredential userCredential, String mailboxId, int expectedNumberOfMessages) { + assertThat(JmapRFCCommonRequests.listMessageIdsInMailbox(userCredential, mailboxId)) + .hasSize(expectedNumberOfMessages); } - default List<Map<String, String>> getAllMailboxesIds(AccessToken accessToken) { - return with() - .header("Authorization", accessToken.asString()) - .body("[[\"getMailboxes\", {\"properties\": [\"role\", \"id\"]}, \"#0\"]]") - .post("/jmap") - .andReturn() - .body() - .jsonPath() - .getList(ARGUMENTS + ".list"); - } - - default String getInboxId(AccessToken accessToken) { - return getMailboxId(accessToken, Role.INBOX); - } - - default String getOutboxId(AccessToken accessToken) { - return getMailboxId(accessToken, Role.OUTBOX); + default String getInboxId(UserCredential userCredential) { + return JmapRFCCommonRequests.getMailboxId(userCredential, Role.INBOX); } - default String getSpamId(AccessToken accessToken) { - return getMailboxId(accessToken, Role.SPAM); + default String getSpamId(UserCredential userCredential) { + return JmapRFCCommonRequests.getMailboxId(userCredential,Role.SPAM); } - default String getTrashId(AccessToken accessToken) { - return getMailboxId(accessToken, Role.TRASH); + default String getTrashId(UserCredential userCredential) { + return JmapRFCCommonRequests.getMailboxId(userCredential,Role.TRASH); } default void assertEveryListenerGotCalled(GuiceJamesServer jamesServer) { @@ -694,8 +590,28 @@ public interface SpamAssassinContract { .isTrue(); } - private URIBuilder baseUri(GuiceJamesServer jamesServer) { - return LocalHostURIBuilder.baseUri( - Port.of(jamesServer.getProbe(JmapGuiceProbe.class).getJmapPort().getValue())); + private void moveMessagesToNewMailbox(List<String> messageIds, String newMailboxId, UserCredential userCredential) { + Consumer<String> moveMessagesToNewMailbox = messageId -> given() + .auth().basic(userCredential.username().asString(), userCredential.password()) + .body(""" + { + "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], + "methodCalls": [ + ["Email/set", { + "accountId": "%s", + "update": { + "%s":{ + "mailboxIds": { "%s" : true} + } + } + }, "c1"]] + }""".formatted(userCredential.accountId(), messageId, newMailboxId)) + .when() + .post("/jmap") + .then() + .statusCode(200) + .contentType(JSON); + + messageIds.forEach(moveMessagesToNewMailbox); } } diff --git a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/module/SpamAssassinTestModule.java b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/module/SpamAssassinTestModule.java index 204bdb26fb..dc472448b4 100644 --- a/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/module/SpamAssassinTestModule.java +++ b/third-party/spamassassin/src/test/java/org/apache/james/spamassassin/module/SpamAssassinTestModule.java @@ -21,19 +21,16 @@ package org.apache.james.spamassassin.module; import jakarta.inject.Singleton; -import org.apache.james.mailetcontainer.impl.MailetConfigImpl; +import org.apache.james.jmap.event.PopulateEmailQueryViewListener; import org.apache.james.modules.mailbox.ListenerConfiguration; import org.apache.james.modules.mailbox.ListenersConfiguration; -import org.apache.james.spamassassin.SpamAssassin; import org.apache.james.spamassassin.SpamAssassinConfiguration; import org.apache.james.spamassassin.SpamAssassinExtension; import org.apache.james.spamassassin.SpamAssassinListener; import org.apache.james.util.Host; -import org.apache.james.utils.MailetConfigurationOverride; import com.google.inject.AbstractModule; import com.google.inject.Provides; -import com.google.inject.multibindings.Multibinder; public class SpamAssassinTestModule extends AbstractModule { @@ -47,7 +44,8 @@ public class SpamAssassinTestModule extends AbstractModule { protected void configure() { bind(ListenersConfiguration.class) .toInstance(ListenersConfiguration.of( - ListenerConfiguration.forClass(SpamAssassinListener.class.getCanonicalName()))); + ListenerConfiguration.forClass(SpamAssassinListener.class.getCanonicalName()), + ListenerConfiguration.forClass(PopulateEmailQueryViewListener.class.getCanonicalName()))); } @Provides --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
