This is an automated email from the ASF dual-hosted git repository. quantranhong1999 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 9c32331b311781208f47427e6882c2df1c89b575 Author: Quan Tran <[email protected]> AuthorDate: Fri Jun 19 17:04:09 2026 +0700 [BUILD] WebSocketContract: isolate using different users ### Before - memory: 25 sec - postgres: 26 sec - distributed: 3 min ### After - memory: 12 sec - postgres: 14 sec - distributed: 21 sec --- .../distributed/DistributedWebSocketTest.java | 2 +- .../jmap/rfc8621/contract/WebSocketContract.scala | 224 ++++++++++++--------- .../jmap/rfc8621/memory/MemoryWebSocketTest.java | 2 +- .../rfc8621/postgres/PostgresWebSocketTest.java | 2 +- 4 files changed, 129 insertions(+), 101 deletions(-) diff --git a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedWebSocketTest.java b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedWebSocketTest.java index cdc66e9fca..6af1b1f5ad 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedWebSocketTest.java +++ b/server/protocols/jmap-rfc-8621-integration-tests/distributed-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/distributed/DistributedWebSocketTest.java @@ -21,6 +21,6 @@ package org.apache.james.jmap.rfc8621.distributed; import org.apache.james.jmap.rfc8621.contract.WebSocketContract; -public class DistributedWebSocketTest extends DistributedBase implements WebSocketContract { +public class DistributedWebSocketTest extends PerClassDistributedBase implements WebSocketContract { } diff --git a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala index 7de3da9854..e4fc62771a 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala +++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/WebSocketContract.scala @@ -20,8 +20,11 @@ package org.apache.james.jmap.rfc8621.contract import java.net.{ProtocolException, URI} import java.nio.charset.StandardCharsets +import java.util.UUID import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicReference +import com.google.common.hash.Hashing import net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson import org.apache.james.GuiceJamesServer import org.apache.james.core.Username @@ -30,6 +33,7 @@ import org.apache.james.jmap.api.change.State import org.apache.james.jmap.api.model.AccountId import org.apache.james.jmap.core.{PushState, UuidState} import org.apache.james.jmap.rfc8621.contract.Fixture._ +import org.apache.james.jmap.rfc8621.contract.WebSocketContract.TestContext import org.apache.james.jmap.rfc8621.contract.probe.DelegationProbe import org.apache.james.mailbox.MessageManager.AppendCommand import org.apache.james.mailbox.model.MailboxACL.Right @@ -57,7 +61,20 @@ import sttp.ws.{WebSocket, WebSocketFrame} import scala.jdk.CollectionConverters._ import scala.util.Try +object WebSocketContract { + case class TestContext(bobUsername: Username, bobAccountId: String, + andreUsername: Username, + davidUsername: Username, davidAccountId: String) + val currentContext: AtomicReference[TestContext] = new AtomicReference[TestContext]() +} + trait WebSocketContract { + def bobUsername: Username = WebSocketContract.currentContext.get().bobUsername + def bobAccountId: String = WebSocketContract.currentContext.get().bobAccountId + def andreUsername: Username = WebSocketContract.currentContext.get().andreUsername + def davidUsername: Username = WebSocketContract.currentContext.get().davidUsername + def davidAccountId: String = WebSocketContract.currentContext.get().davidAccountId + private lazy val awaitAtMostTenSeconds: ConditionFactory = Awaitility.`with` .pollInterval(ONE_HUNDRED_MILLISECONDS) .and.`with`.pollDelay(ONE_HUNDRED_MILLISECONDS) @@ -68,12 +85,23 @@ trait WebSocketContract { @BeforeEach def setUp(server: GuiceJamesServer): Unit = { + val uniqueSuffix = UUID.randomUUID().toString.replace("-", "").take(8) + val bob = Username.fromLocalPartWithDomain(s"bob$uniqueSuffix", DOMAIN) + val andre = Username.fromLocalPartWithDomain(s"andre$uniqueSuffix", DOMAIN) + val david = Username.fromLocalPartWithDomain(s"david$uniqueSuffix", DOMAIN) + WebSocketContract.currentContext.set(TestContext( + bobUsername = bob, + bobAccountId = Hashing.sha256().hashString(bob.asString(), StandardCharsets.UTF_8).toString, + andreUsername = andre, + davidUsername = david, + davidAccountId = Hashing.sha256().hashString(david.asString(), StandardCharsets.UTF_8).toString)) + server.getProbe(classOf[DataProbeImpl]) .fluent() .addDomain(DOMAIN.asString()) - .addUser(ANDRE.asString(), ANDRE_PASSWORD) - .addUser(BOB.asString(), BOB_PASSWORD) - .addUser(DAVID.asString(), "secret") + .addUser(andre.asString(), ANDRE_PASSWORD) + .addUser(bob.asString(), BOB_PASSWORD) + .addUser(david.asString(), "secret") } @Test @@ -417,7 +445,7 @@ trait WebSocketContract { .response(asWebSocket[Identity, String] { ws => ws.send(WebSocketFrame.text( - """{ + s"""{ | "@type": "Request", | "using": [ | "urn:ietf:params:jmap:core", @@ -425,7 +453,7 @@ trait WebSocketContract { | "methodCalls": [[ | "Mailbox/get", | { - | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "accountId": "$bobAccountId", | "properties": ["invalidProperty"] | }, | "c1"]] @@ -448,8 +476,8 @@ trait WebSocketContract { @Test @Timeout(180) def pushEnableRequestsShouldBeProcessed(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -473,7 +501,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -498,7 +526,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(2) // state change notification + API response @@ -508,10 +536,10 @@ trait WebSocketContract { @Test @Timeout(180) def moveShouldGenerateSingleStateChange(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) - val mailboxId2 = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(BOB, "abc")) + val mailboxId2 = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.forUser(bobUsername, "abc")) Thread.sleep(100) @@ -534,7 +562,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -544,7 +572,7 @@ trait WebSocketContract { | } | }, "c1"], | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "update": { | "#aaaaaa":{ | "mailboxIds": { @@ -573,7 +601,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(3) // (create) state change notification + (update) state change notification + API response @@ -585,18 +613,18 @@ trait WebSocketContract { def bulkMoveWithNonContiguousUidsShouldGenerateSingleStateChange(server: GuiceJamesServer): Unit = { // Moving N emails with non-contiguous UIDs (gap in the UID sequence) should // still produce only ONE state change, not one per UID range. - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl]) val mailboxId = mailboxProbe.createMailbox(bobPath) - val mailboxId2 = mailboxProbe.createMailbox(MailboxPath.forUser(BOB, "destination")) + val mailboxId2 = mailboxProbe.createMailbox(MailboxPath.forUser(bobUsername, "destination")) // Append 5 messages (UIDs will be 1, 2, 3, 4, 5) - val message1 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test1").setBody("body1", StandardCharsets.UTF_8).build())) - val message2 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test2").setBody("body2", StandardCharsets.UTF_8).build())) - mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test3").setBody("body3", StandardCharsets.UTF_8).build())) // UID 3 intentionally NOT moved - val message4 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test4").setBody("body4", StandardCharsets.UTF_8).build())) - val message5 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test5").setBody("body5", StandardCharsets.UTF_8).build())) + val message1 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test1").setBody("body1", StandardCharsets.UTF_8).build())) + val message2 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test2").setBody("body2", StandardCharsets.UTF_8).build())) + mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test3").setBody("body3", StandardCharsets.UTF_8).build())) // UID 3 intentionally NOT moved + val message4 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test4").setBody("body4", StandardCharsets.UTF_8).build())) + val message5 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test5").setBody("body5", StandardCharsets.UTF_8).build())) // Move messages 1, 2, 4, 5 — skipping UID 3 — producing 2 UID ranges: [1,2] and [4,5] val messageId1 = message1.getMessageId.serialize() @@ -625,7 +653,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "update": { | "$messageId1": {"mailboxIds": {"${mailboxId2.serialize}": true}}, | "$messageId2": {"mailboxIds": {"${mailboxId2.serialize}": true}}, @@ -650,7 +678,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(2) // 1 state change notification + 1 API response (not 2 state changes) @@ -663,17 +691,17 @@ trait WebSocketContract { // Flagging N emails with non-contiguous UIDs (gap in the UID sequence) should // still produce only ONE state change, not one per UID range. // The optimization path (updateFlagsByRange) is triggered when sameUpdate && singleMailbox && size > RANGE_THRESHOLD (3). - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxProbe = server.getProbe(classOf[MailboxProbeImpl]) mailboxProbe.createMailbox(bobPath) // Append 5 messages (UIDs will be 1, 2, 3, 4, 5) - val message1 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test1").setBody("body1", StandardCharsets.UTF_8).build())) - val message2 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test2").setBody("body2", StandardCharsets.UTF_8).build())) - mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test3").setBody("body3", StandardCharsets.UTF_8).build())) // UID 3 intentionally NOT flagged - val message4 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test4").setBody("body4", StandardCharsets.UTF_8).build())) - val message5 = mailboxProbe.appendMessage(BOB.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test5").setBody("body5", StandardCharsets.UTF_8).build())) + val message1 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test1").setBody("body1", StandardCharsets.UTF_8).build())) + val message2 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test2").setBody("body2", StandardCharsets.UTF_8).build())) + mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test3").setBody("body3", StandardCharsets.UTF_8).build())) // UID 3 intentionally NOT flagged + val message4 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test4").setBody("body4", StandardCharsets.UTF_8).build())) + val message5 = mailboxProbe.appendMessage(bobUsername.asString(), bobPath, AppendCommand.from(Message.Builder.of().setSubject("test5").setBody("body5", StandardCharsets.UTF_8).build())) // Flag messages 1, 2, 4, 5 — skipping UID 3 — producing 2 UID ranges: [1,2] and [4,5] val messageId1 = message1.getMessageId.serialize() @@ -702,7 +730,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "update": { | "$messageId1": {"keywords/$$seen": true}, | "$messageId2": {"keywords/$$seen": true}, @@ -727,7 +755,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(2) // 1 state change notification + 1 API response (not 2 state changes) @@ -737,11 +765,11 @@ trait WebSocketContract { @Test @Timeout(180) def shouldPushChangesToDelegatedUser(server: GuiceJamesServer): Unit = { - val davidPath = MailboxPath.inbox(DAVID) + val davidPath = MailboxPath.inbox(davidUsername) server.getProbe(classOf[MailboxProbeImpl]).createMailbox(davidPath) - // DAVID delegates BOB to access his account - server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(DAVID, BOB) + // davidUsername delegates bobUsername to access his account + server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(davidUsername, bobUsername) Thread.sleep(100) @@ -757,8 +785,8 @@ trait WebSocketContract { Thread.sleep(100) - // DAVID has a new mail therefore EmailDelivery change - sendEmailTo(server, DAVID) + // davidUsername has a new mail therefore EmailDelivery change + sendEmailTo(server, davidUsername) List( ws.receive().asPayload) @@ -768,22 +796,22 @@ trait WebSocketContract { Thread.sleep(100) - // Bob should receive DAVID's EmailDelivery state change + // Bob should receive davidUsername's EmailDelivery state change assertThat(response.toOption.get.asJava) .hasSize(1) assertThatJson(response.toOption.get.asJava.get(0)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$DAVID_ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$davidAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) } @Test @Timeout(180) def ownerUserShouldStillReceiveHisChangesWhenHeDelegatesHisAccountToOtherUsers(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) + val bobPath = MailboxPath.inbox(bobUsername) server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) - // BOB delegates DAVID to access his account - server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(BOB, DAVID) + // bobUsername delegates davidUsername to access his account + server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(bobUsername, davidUsername) Thread.sleep(100) @@ -799,8 +827,8 @@ trait WebSocketContract { Thread.sleep(100) - // BOB has a new mail therefore EmailDelivery change - sendEmailTo(server, BOB) + // bobUsername has a new mail therefore EmailDelivery change + sendEmailTo(server, bobUsername) List( ws.receive().asPayload) @@ -815,17 +843,17 @@ trait WebSocketContract { .hasSize(1) assertThatJson(response.toOption.get.asJava.get(0)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$bobAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) } @Test @Timeout(180) def bobShouldReceiveHisChangesAndHisDelegatedAccountChanges(server: GuiceJamesServer): Unit = { - val davidPath = MailboxPath.inbox(DAVID) + val davidPath = MailboxPath.inbox(davidUsername) server.getProbe(classOf[MailboxProbeImpl]).createMailbox(davidPath) - // DAVID delegates BOB to access his account - server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(DAVID, BOB) + // davidUsername delegates bobUsername to access his account + server.getProbe(classOf[DelegationProbe]).addAuthorizedUser(davidUsername, bobUsername) Thread.sleep(100) @@ -841,10 +869,10 @@ trait WebSocketContract { Thread.sleep(100) - sendEmailTo(server, DAVID) - sendEmailTo(server, BOB) - sendEmailTo(server, DAVID) - sendEmailTo(server, BOB) + sendEmailTo(server, davidUsername) + sendEmailTo(server, bobUsername) + sendEmailTo(server, davidUsername) + sendEmailTo(server, bobUsername) List( ws.receive().asPayload, @@ -857,23 +885,23 @@ trait WebSocketContract { Thread.sleep(100) - // Bob should receive DAVID's change and his changes + // Bob should receive davidUsername's change and his changes assertThat(response.toOption.get.asJava) .hasSize(4) assertThatJson(response.toOption.get.asJava.get(0)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$DAVID_ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$davidAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) assertThatJson(response.toOption.get.asJava.get(1)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$bobAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) assertThatJson(response.toOption.get.asJava.get(2)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$DAVID_ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$davidAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) assertThatJson(response.toOption.get.asJava.get(1)) - .isEqualTo(s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) + .isEqualTo(s"""{"@type":"StateChange","changed":{"$bobAccountId":{"EmailDelivery":"$${json-unit.ignore}"}},"pushState":"$${json-unit.ignore}"}""".stripMargin) } @Test @Timeout(180) def mixingPushAndResponsesShouldBeSupported(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) + val bobPath = MailboxPath.inbox(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -885,7 +913,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -944,7 +972,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail", "urn:ietf:params:jmap:vacationresponse"], | "methodCalls": [ | ["VacationResponse/set", { - | "accountId": "29883977c13473ae7cb7678ef767cbfbaffc8a44a6e463d971d23a65c1dc4af6", + | "accountId": "$bobAccountId", | "update": { | "singleton": { | "isEnabled": true, @@ -975,8 +1003,8 @@ trait WebSocketContract { @Timeout(180) // For client compatibility purposes def specifiedUnHandledDataTypesShouldNotBeRejected(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -1000,7 +1028,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1025,7 +1053,7 @@ trait WebSocketContract { val emailState: State = jmapGuiceProbe.getLatestEmailState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(2) // state change notification + API response @@ -1036,7 +1064,7 @@ trait WebSocketContract { @Timeout(180) // For client compatibility purposes def emailDeliveryShouldNotIncludeFlagUpdatesAndDeletes(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) + val bobPath = MailboxPath.inbox(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -1052,7 +1080,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1089,7 +1117,7 @@ trait WebSocketContract { | "@type": "Request", | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "update": { | "$messageId":{ | "keywords": { @@ -1111,7 +1139,7 @@ trait WebSocketContract { | "@type": "Request", | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "destroy": ["$messageId"] | }, "c1"]] |}""".stripMargin)) @@ -1136,8 +1164,8 @@ trait WebSocketContract { @Test @Timeout(180) def dataTypesShouldDefaultToAll(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -1161,7 +1189,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1186,7 +1214,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(2) // state change notification + API response @@ -1196,7 +1224,7 @@ trait WebSocketContract { @Test @Timeout(180) def shouldPushEmailDeliveryChangeWhenUserReceivesEmail(server: GuiceJamesServer): Unit = { - server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB)) + server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(bobUsername)) val response: Either[String, List[String]] = authenticatedRequest(server) @@ -1211,7 +1239,7 @@ trait WebSocketContract { Thread.sleep(100) // Andre send mail to Bob - sendEmailTo(server, BOB) + sendEmailTo(server, bobUsername) List( ws.receive().asPayload) @@ -1228,7 +1256,7 @@ trait WebSocketContract { @Test @Timeout(180) def shouldNotPushEmailDeliveryChangeWhenCreateDraftMail(server: GuiceJamesServer): Unit = { - val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(BOB)) + val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(MailboxPath.inbox(bobUsername)) val response: Either[String, List[String]] = authenticatedRequest(server) @@ -1249,7 +1277,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1275,9 +1303,9 @@ trait WebSocketContract { @Test @Timeout(180) def pushEnableShouldUpdatePreviousSubscriptions(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) + val bobPath = MailboxPath.inbox(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) - val accountId: AccountId = AccountId.fromUsername(BOB) + val accountId: AccountId = AccountId.fromUsername(bobUsername) Thread.sleep(100) val response: Either[String, List[String]] = @@ -1307,7 +1335,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1330,7 +1358,7 @@ trait WebSocketContract { val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val mailboxStateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""" + val mailboxStateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""" assertThat(response.toOption.get.asJava) .hasSize(2) // Method response + Mailbox state change, no Email notification @@ -1341,11 +1369,11 @@ trait WebSocketContract { @Timeout(180) def pushShouldSupportDelegation(server: GuiceJamesServer): Unit = { val mailboxProbe: MailboxProbeImpl = server.getProbe(classOf[MailboxProbeImpl]) - val andrePath = MailboxPath.inbox(ANDRE) + val andrePath = MailboxPath.inbox(andreUsername) mailboxProbe.createMailbox(andrePath) server.getProbe(classOf[ACLProbeImpl]) - .replaceRights(andrePath, BOB.asString, new MailboxACL.Rfc4314Rights(Right.Lookup, Right.Read)) + .replaceRights(andrePath, bobUsername.asString, new MailboxACL.Rfc4314Rights(Right.Lookup, Right.Read)) Thread.sleep(100) @@ -1366,7 +1394,7 @@ trait WebSocketContract { .setSubject("test") .setBody("testmail", StandardCharsets.UTF_8) .build - mailboxProbe.appendMessage(ANDRE.asString(), andrePath, AppendCommand.from(message)) + mailboxProbe.appendMessage(andreUsername.asString(), andrePath, AppendCommand.from(message)) Thread.sleep(100) @@ -1378,12 +1406,12 @@ trait WebSocketContract { Thread.sleep(100) val jmapGuiceProbe: JmapGuiceProbe = server.getProbe(classOf[JmapGuiceProbe]) - val accountId: AccountId = AccountId.fromUsername(BOB) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val emailState: State = jmapGuiceProbe.getLatestEmailStateWithDelegation(accountId) val mailboxState: State = jmapGuiceProbe.getLatestMailboxStateWithDelegation(accountId) val globalState: String = PushState.fromOption(Some(UuidState.fromJava(mailboxState)), Some(UuidState.fromJava(emailState))).get.value - val stateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin + val stateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"${emailState.getValue}","Mailbox":"${mailboxState.getValue}"}},"pushState":"$globalState"}""".stripMargin assertThat(response.toOption.get.asJava) .hasSize(1) @@ -1393,8 +1421,8 @@ trait WebSocketContract { @Test @Timeout(180) def pushCancelRequestsShouldDisableNotification(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) val mailboxId = server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -1425,7 +1453,7 @@ trait WebSocketContract { | "using": ["urn:ietf:params:jmap:core", "urn:ietf:params:jmap:mail"], | "methodCalls": [ | ["Email/set", { - | "accountId": "$ACCOUNT_ID", + | "accountId": "$bobAccountId", | "create": { | "aaaaaa":{ | "mailboxIds": { @@ -1454,8 +1482,8 @@ trait WebSocketContract { val emailState: String = jmapGuiceProbe.getLatestEmailState(accountId).getValue.toString val mailboxState: String = jmapGuiceProbe.getLatestMailboxState(accountId).getValue.toString - val mailboxStateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Mailbox":"$mailboxState"}}}""" - val emailStateChange: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Email":"$emailState"}}}""" + val mailboxStateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Mailbox":"$mailboxState"}}}""" + val emailStateChange: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Email":"$emailState"}}}""" assertThat(response.toOption.get.asJava) .hasSize(2) // Email create response + no notification message @@ -1487,8 +1515,8 @@ trait WebSocketContract { @Test @Timeout(180) def pushEnableRequestWithPushStateShouldReturnServerState(server: GuiceJamesServer): Unit = { - val bobPath = MailboxPath.inbox(BOB) - val accountId: AccountId = AccountId.fromUsername(BOB) + val bobPath = MailboxPath.inbox(bobUsername) + val accountId: AccountId = AccountId.fromUsername(bobUsername) server.getProbe(classOf[MailboxProbeImpl]).createMailbox(bobPath) Thread.sleep(100) @@ -1516,7 +1544,7 @@ trait WebSocketContract { val emailState: State = jmapGuiceProbe.getLatestEmailState(accountId) val mailboxState: State = jmapGuiceProbe.getLatestMailboxState(accountId) val globalState: PushState = PushState.from(UuidState(mailboxState.getValue), UuidState(emailState.getValue)) - val pushEnableResponse: String = s"""{"@type":"StateChange","changed":{"$ACCOUNT_ID":{"Mailbox":"${mailboxState.getValue}","Email":"${emailState.getValue}"}},"pushState":"${globalState.value}"}""" + val pushEnableResponse: String = s"""{"@type":"StateChange","changed":{"$bobAccountId":{"Mailbox":"${mailboxState.getValue}","Email":"${emailState.getValue}"}},"pushState":"${globalState.value}"}""" assertThat(response.toOption.get) .isEqualTo(pushEnableResponse) @@ -1528,7 +1556,7 @@ trait WebSocketContract { .getValue basicRequest.get(Uri.apply(new URI(s"ws://127.0.0.1:$port/jmap/ws"))) - .header("Authorization", "Basic Ym9iQGRvbWFpbi50bGQ6Ym9icGFzc3dvcmQ=") + .header("Authorization", s"Basic ${toBase64(s"${bobUsername.asString}:$BOB_PASSWORD")}") .header("Accept", ACCEPT_RFC8621_VERSION_HEADER) } @@ -1544,8 +1572,8 @@ trait WebSocketContract { private def sendEmailTo(server: GuiceJamesServer, recipient: Username): Unit = { val smtpMessageSender: SMTPMessageSender = new SMTPMessageSender(DOMAIN.asString()) smtpMessageSender.connect("127.0.0.1", server.getProbe(classOf[SmtpGuiceProbe]).getSmtpPort) - .authenticate(ANDRE.asString, ANDRE_PASSWORD) - .sendMessage(ANDRE.asString, recipient.asString()) + .authenticate(andreUsername.asString, ANDRE_PASSWORD) + .sendMessage(andreUsername.asString, recipient.asString()) smtpMessageSender.close() awaitAtMostTenSeconds.until(() => server.getProbe(classOf[SpoolerProbe]).processingFinished()) diff --git a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryWebSocketTest.java b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryWebSocketTest.java index ecae80d554..23854c95f5 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryWebSocketTest.java +++ b/server/protocols/jmap-rfc-8621-integration-tests/memory-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/memory/MemoryWebSocketTest.java @@ -21,5 +21,5 @@ package org.apache.james.jmap.rfc8621.memory; import org.apache.james.jmap.rfc8621.contract.WebSocketContract; -public class MemoryWebSocketTest extends MemoryBase implements WebSocketContract { +public class MemoryWebSocketTest extends PerClassMemoryBase implements WebSocketContract { } diff --git a/server/protocols/jmap-rfc-8621-integration-tests/postgres-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/postgres/PostgresWebSocketTest.java b/server/protocols/jmap-rfc-8621-integration-tests/postgres-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/postgres/PostgresWebSocketTest.java index c16d808925..f13b90f432 100644 --- a/server/protocols/jmap-rfc-8621-integration-tests/postgres-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/postgres/PostgresWebSocketTest.java +++ b/server/protocols/jmap-rfc-8621-integration-tests/postgres-jmap-rfc-8621-integration-tests/src/test/java/org/apache/james/jmap/rfc8621/postgres/PostgresWebSocketTest.java @@ -21,5 +21,5 @@ package org.apache.james.jmap.rfc8621.postgres; import org.apache.james.jmap.rfc8621.contract.WebSocketContract; -public class PostgresWebSocketTest extends PostgresBase implements WebSocketContract { +public class PostgresWebSocketTest extends PerClassPostgresBase implements WebSocketContract { } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
