You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/07/06 01:37:04 UTC

[james-project] 02/05: JAMES-3095 Only retrieve requested mailboxes

This is an automated email from the ASF dual-hosted git repository.

btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 672b9101c0b343b126c27ebd0f5dc0d8bf2ba746
Author: Rene Cordier <rc...@linagora.com>
AuthorDate: Thu Jun 25 11:08:28 2020 +0700

    JAMES-3095 Only retrieve requested mailboxes
---
 .../contract/MailboxGetMethodContract.scala        |   2 +-
 .../org/apache/james/jmap/json/Serializer.scala    |   4 +-
 .../org/apache/james/jmap/mail/MailboxGet.scala    |   2 +-
 .../james/jmap/method/MailboxGetMethod.scala       |  41 +++---
 .../apache/james/jmap/model/MailboxFactory.scala   | 156 +++++++++++++++------
 .../jmap/json/MailboxGetSerializationTest.scala    |   2 +-
 6 files changed, 136 insertions(+), 71 deletions(-)

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/MailboxGetMethodContract.scala b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
index 1c1a027..b079138 100644
--- a/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
+++ b/server/protocols/jmap-rfc-8621-integration-tests/jmap-rfc-8621-integration-tests-common/src/main/scala/org/apache/james/jmap/rfc8621/contract/MailboxGetMethodContract.scala
@@ -621,7 +621,7 @@ trait MailboxGetMethodContract {
   }
 
   @Test
-  def getMailboxesByIdsShouldReturnMailboxesInSorteredOrder(server: GuiceJamesServer): Unit = {
+  def getMailboxesByIdsShouldReturnMailboxesInSortedOrder(server: GuiceJamesServer): Unit = {
     val mailboxId1: String = server.getProbe(classOf[MailboxProbeImpl])
       .createMailbox(MailboxPath.forUser(BOB, DefaultMailboxes.TRASH))
       .serialize
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
index 76c6863..e6d26e3 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/json/Serializer.scala
@@ -207,7 +207,9 @@ class Serializer @Inject() (mailboxIdFactory: MailboxId.Factory) {
   private implicit val propertiesRead: Reads[Properties] = Json.valueReads[Properties]
   private implicit val mailboxGetRequest: Reads[MailboxGetRequest] = Json.reads[MailboxGetRequest]
 
-  private implicit val notFoundWrites: Writes[NotFound] = Json.valueWrites[NotFound]
+  private implicit def notFoundWrites(implicit mailboxIdWrites: Writes[MailboxId]): Writes[NotFound] =
+    notFound => JsArray(notFound.value.toList.map(mailboxIdWrites.writes))
+
   private implicit val mailboxGetResponseWrites: Writes[MailboxGetResponse] = Json.writes[MailboxGetResponse]
 
   private implicit val jsonValidationErrorWrites: Writes[JsonValidationError] = error => JsString(error.message)
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
index a4400ee..5d9b971 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/mail/MailboxGet.scala
@@ -32,7 +32,7 @@ case class MailboxGetRequest(accountId: AccountId,
                              ids: Option[Ids],
                              properties: Option[Properties])
 
-case class NotFound(value: List[MailboxId]) {
+case class NotFound(value: Set[MailboxId]) {
   def merge(other: NotFound): NotFound = NotFound(this.value ++ other.value)
 }
 
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
index 6eaea11..b3c66c1 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/method/MailboxGetMethod.scala
@@ -27,6 +27,7 @@ import org.apache.james.jmap.model.Invocation.{Arguments, MethodName}
 import org.apache.james.jmap.model.State.INSTANCE
 import org.apache.james.jmap.model.{Invocation, MailboxFactory}
 import org.apache.james.jmap.utils.quotas.{QuotaLoader, QuotaLoaderWithPreloadedDefaultFactory}
+import org.apache.james.mailbox.exception.MailboxNotFoundException
 import org.apache.james.mailbox.model.search.MailboxQuery
 import org.apache.james.mailbox.model.{MailboxId, MailboxMetaData}
 import org.apache.james.mailbox.{MailboxManager, MailboxSession}
@@ -44,11 +45,11 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
   override val methodName: MethodName = MethodName("Mailbox/get")
 
   object MailboxGetResults {
-    def found(mailbox: Mailbox): MailboxGetResults = MailboxGetResults(List(mailbox), NotFound(Nil))
-    def notFound(mailboxId: MailboxId): MailboxGetResults = MailboxGetResults(Nil, NotFound(List(mailboxId)))
+    def found(mailbox: Mailbox): MailboxGetResults = MailboxGetResults(Set(mailbox), NotFound(Set.empty))
+    def notFound(mailboxId: MailboxId): MailboxGetResults = MailboxGetResults(Set.empty, NotFound(Set(mailboxId)))
   }
 
-  case class MailboxGetResults(mailboxes: List[Mailbox], notFound: NotFound) {
+  case class MailboxGetResults(mailboxes: Set[Mailbox], notFound: NotFound) {
     def merge(other: MailboxGetResults): MailboxGetResults = MailboxGetResults(this.mailboxes ++ other.mailboxes, this.notFound.merge(other.notFound))
   }
 
@@ -56,11 +57,11 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
     metricFactory.decoratePublisherWithTimerMetricLogP99(JMAP_RFC8621_PREFIX + methodName.value,
       asMailboxGetRequest(invocation.arguments)
         .flatMap(mailboxGetRequest => getMailboxes(mailboxGetRequest, mailboxSession)
-          .reduce(MailboxGetResults(Nil, NotFound(Nil)), (result1: MailboxGetResults, result2: MailboxGetResults) => result1.merge(result2))
+          .reduce(MailboxGetResults(Set.empty, NotFound(Set.empty)), (result1: MailboxGetResults, result2: MailboxGetResults) => result1.merge(result2))
           .map(mailboxes => MailboxGetResponse(
             accountId = mailboxGetRequest.accountId,
             state = INSTANCE,
-            list = mailboxes.mailboxes.sortBy(_.sortOrder),
+            list = mailboxes.mailboxes.toList.sortBy(_.sortOrder),
             notFound = mailboxes.notFound))
           .map(mailboxGetResponse => Invocation(
             methodName = methodName,
@@ -77,18 +78,20 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
 
   private def getMailboxes(mailboxGetRequest: MailboxGetRequest, mailboxSession: MailboxSession): SFlux[MailboxGetResults] = mailboxGetRequest.ids match {
     case None => getAllMailboxes(mailboxSession).map(MailboxGetResults.found)
-    case Some(ids) =>
-      getAllMailboxes(mailboxSession)
-        .collectSeq()
-        .flatMapMany(mailboxes => SFlux.merge(Seq(
-          SFlux.fromIterable(mailboxes)
-            .filter(mailbox => ids.value.contains(mailbox.id))
-            .map(MailboxGetResults.found),
-          SFlux.fromIterable(ids.value)
-            .filter(id => !mailboxes.map(_.id).contains(id))
-            .map(MailboxGetResults.notFound))))
+    case Some(ids) => SFlux.fromIterable(ids.value)
+      .flatMap(id => getMailboxResultById(id, mailboxSession))
   }
 
+  private def getMailboxResultById(mailboxId: MailboxId, mailboxSession: MailboxSession): SMono[MailboxGetResults] =
+    quotaFactory.loadFor(mailboxSession)
+      .flatMap(quotaLoader => mailboxFactory.create(mailboxId, mailboxSession, quotaLoader)
+        .map(MailboxGetResults.found)
+        .onErrorResume {
+          case _: MailboxNotFoundException => SMono.just(MailboxGetResults.notFound(mailboxId))
+          case error => SMono.raiseError(error)
+        })
+      .subscribeOn(Schedulers.elastic)
+
   private def getAllMailboxes(mailboxSession: MailboxSession): SFlux[Mailbox] = {
     quotaFactory.loadFor(mailboxSession)
       .subscribeOn(Schedulers.elastic)
@@ -96,7 +99,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
         getAllMailboxesMetaData(mailboxSession).flatMapMany(mailboxesMetaData =>
           SFlux.fromIterable(mailboxesMetaData)
             .flatMap(mailboxMetaData =>
-              getMailboxOrThrow(mailboxMetaData = mailboxMetaData,
+              getMailboxResult(mailboxMetaData = mailboxMetaData,
                 mailboxSession = mailboxSession,
                 allMailboxesMetadata = mailboxesMetaData,
                 quotaLoader = quotaLoader))))
@@ -106,7 +109,7 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
     SFlux.fromPublisher(mailboxManager.search(MailboxQuery.builder.matchesAllMailboxNames.build, mailboxSession))
       .collectSeq()
 
-  private def getMailboxOrThrow(mailboxSession: MailboxSession,
+  private def getMailboxResult(mailboxSession: MailboxSession,
                                 allMailboxesMetadata: Seq[MailboxMetaData],
                                 mailboxMetaData: MailboxMetaData,
                                 quotaLoader: QuotaLoader): SMono[Mailbox] =
@@ -114,8 +117,4 @@ class MailboxGetMethod @Inject() (serializer: Serializer,
       mailboxSession = mailboxSession,
       allMailboxesMetadata = allMailboxesMetadata,
       quotaLoader = quotaLoader)
-      .flatMap {
-        case Left(error) => SMono.raiseError(error)
-        case scala.Right(mailbox) => SMono.just(mailbox)
-      }
 }
diff --git a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala
index 98c3eb7..738b0f9 100644
--- a/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala
+++ b/server/protocols/jmap-rfc-8621/src/main/scala/org/apache/james/jmap/model/MailboxFactory.scala
@@ -24,9 +24,9 @@ import org.apache.james.jmap.mail.MailboxName.MailboxName
 import org.apache.james.jmap.mail._
 import org.apache.james.jmap.model.UnsignedInt.UnsignedInt
 import org.apache.james.jmap.utils.quotas.QuotaLoader
+import org.apache.james.mailbox._
 import org.apache.james.mailbox.model.MailboxACL.EntryKey
 import org.apache.james.mailbox.model.{MailboxCounters, MailboxId, MailboxMetaData, MailboxPath, MailboxACL => JavaMailboxACL}
-import org.apache.james.mailbox.{MailboxSession, Role, SubscriptionManager}
 import reactor.core.scala.publisher.SMono
 
 import scala.jdk.CollectionConverters._
@@ -59,7 +59,7 @@ case class MailboxValidation(mailboxName: MailboxName,
                              totalEmails: TotalEmails,
                              totalThreads: TotalThreads)
 
-class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager) {
+class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager, mailboxManager: MailboxManager) {
 
   private def retrieveMailboxName(mailboxPath: MailboxPath, mailboxSession: MailboxSession): Either[IllegalArgumentException, MailboxName] =
     mailboxPath.getName
@@ -69,20 +69,63 @@ class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager) {
         case None => Left(new IllegalArgumentException("No name for the mailbox found"))
       }
 
+  private def getRole(mailboxPath: MailboxPath, mailboxSession: MailboxSession): Option[Role] = Role.from(mailboxPath.getName)
+    .filter(_ => mailboxPath.belongsTo(mailboxSession)).toScala
+
+  private def getSortOrder(role: Option[Role]): SortOrder = role.map(SortOrder.getSortOrder).getOrElse(SortOrder.defaultSortOrder)
+
+  private def getRights(resolveMailboxACL: JavaMailboxACL): Rights = Rights.fromACL(MailboxACL.fromJava(resolveMailboxACL))
+
+  private def getNamespace(mailboxPath: MailboxPath, mailboxSession: MailboxSession): MailboxNamespace = mailboxPath.belongsTo(mailboxSession) match {
+    case true => PersonalNamespace()
+    case false => DelegatedNamespace(mailboxPath.getUser)
+  }
+
+  private def getParentPath(mailboxPath: MailboxPath, mailboxSession: MailboxSession): Option[MailboxPath] = mailboxPath
+    .getHierarchyLevels(mailboxSession.getPathDelimiter)
+    .asScala
+    .reverse
+    .drop(1)
+    .headOption
+
+  private def aclEntryKey(mailboxSession: MailboxSession): EntryKey = EntryKey.createUserEntryKey(mailboxSession.getUser)
+
+  private def getMyRights(mailboxPath: MailboxPath, resolveMailboxACL: JavaMailboxACL, mailboxSession: MailboxSession): MailboxRights = mailboxPath.belongsTo(mailboxSession) match {
+    case true => MailboxRights.FULL
+    case false =>
+      val rights = Rfc4314Rights.fromJava(resolveMailboxACL
+        .getEntries
+        .getOrDefault(aclEntryKey(mailboxSession), JavaMailboxACL.NO_RIGHTS))
+        .toRights
+      MailboxRights(
+        mayReadItems = MayReadItems(rights.contains(Right.Read)),
+        mayAddItems = MayAddItems(rights.contains(Right.Insert)),
+        mayRemoveItems = MayRemoveItems(rights.contains(Right.DeleteMessages)),
+        maySetSeen = MaySetSeen(rights.contains(Right.Seen)),
+        maySetKeywords = MaySetKeywords(rights.contains(Right.Write)),
+        mayCreateChild = MayCreateChild(false),
+        mayRename = MayRename(false),
+        mayDelete = MayDelete(false),
+        maySubmit = MaySubmit(false))
+  }
+
+  private def retrieveIsSubscribed(path: MailboxPath, session: MailboxSession): IsSubscribed = IsSubscribed(subscriptionManager
+    .subscriptions(session)
+    .contains(path.getName))
+
   def create(mailboxMetaData: MailboxMetaData,
              mailboxSession: MailboxSession,
              allMailboxesMetadata: Seq[MailboxMetaData],
-             quotaLoader: QuotaLoader): SMono[Either[Exception, Mailbox]] = {
+             quotaLoader: QuotaLoader): SMono[Mailbox] = {
 
     val id: MailboxId = mailboxMetaData.getId
 
     val name: Either[IllegalArgumentException, MailboxName] = retrieveMailboxName(mailboxMetaData.getPath, mailboxSession)
 
-    val role: Option[Role] = Role.from(mailboxMetaData.getPath.getName)
-      .filter(_ => mailboxMetaData.getPath.belongsTo(mailboxSession)).toScala
-    val sortOrder: SortOrder = role.map(SortOrder.getSortOrder).getOrElse(SortOrder.defaultSortOrder)
+    val role: Option[Role] = getRole(mailboxMetaData.getPath, mailboxSession)
+    val sortOrder: SortOrder = getSortOrder(role)
     val quotas: SMono[Quotas] = quotaLoader.getQuotas(mailboxMetaData.getPath)
-    val rights: Rights = Rights.fromACL(MailboxACL.fromJava(mailboxMetaData.getResolvedAcls))
+    val rights: Rights = getRights(mailboxMetaData.getResolvedAcls)
 
     val sanitizedCounters: MailboxCounters = mailboxMetaData.getCounters.sanitize()
     val unreadEmails: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getUnseen)
@@ -90,54 +133,22 @@ class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager) {
     val totalEmails: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getCount)
     val totalThreads: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getCount)
 
-    val isOwner = mailboxMetaData.getPath.belongsTo(mailboxSession)
-    val aclEntryKey: EntryKey = EntryKey.createUserEntryKey(mailboxSession.getUser)
-
-    val namespace: MailboxNamespace = if (isOwner) {
-      PersonalNamespace()
-    } else {
-      DelegatedNamespace(mailboxMetaData.getPath.getUser)
-    }
+    val namespace: MailboxNamespace = getNamespace(mailboxMetaData.getPath, mailboxSession)
 
-    val parentPath: Option[MailboxPath] =
-      mailboxMetaData.getPath
-        .getHierarchyLevels(mailboxSession.getPathDelimiter)
-        .asScala
-        .reverse
-        .drop(1)
-        .headOption
+    val parentPath: Option[MailboxPath] = getParentPath(mailboxMetaData.getPath, mailboxSession)
 
     val parentId: Option[MailboxId] = allMailboxesMetadata.filter(otherMetadata => parentPath.contains(otherMetadata.getPath))
       .map(_.getId)
       .headOption
 
-    val myRights: MailboxRights = if (isOwner) {
-      MailboxRights.FULL
-    } else {
-      val rights = Rfc4314Rights.fromJava(mailboxMetaData.getResolvedAcls
-        .getEntries
-        .getOrDefault(aclEntryKey, JavaMailboxACL.NO_RIGHTS))
-        .toRights
-      MailboxRights(
-        mayReadItems = MayReadItems(rights.contains(Right.Read)),
-        mayAddItems = MayAddItems(rights.contains(Right.Insert)),
-        mayRemoveItems = MayRemoveItems(rights.contains(Right.DeleteMessages)),
-        maySetSeen = MaySetSeen(rights.contains(Right.Seen)),
-        maySetKeywords = MaySetKeywords(rights.contains(Right.Write)),
-        mayCreateChild = MayCreateChild(false),
-        mayRename = MayRename(false),
-        mayDelete = MayDelete(false),
-        maySubmit = MaySubmit(false))
-    }
+    val myRights: MailboxRights = getMyRights(mailboxMetaData.getPath, mailboxMetaData.getResolvedAcls, mailboxSession)
 
-    def retrieveIsSubscribed: IsSubscribed = IsSubscribed(subscriptionManager
-      .subscriptions(mailboxSession)
-      .contains(mailboxMetaData.getPath.getName))
+    val isSubscribed: IsSubscribed = retrieveIsSubscribed(mailboxMetaData.getPath, mailboxSession)
 
     MailboxValidation.validate(name, unreadEmails, unreadThreads, totalEmails, totalThreads) match {
-      case Left(error) => SMono.just(Left(error))
+      case Left(error) => SMono.raiseError(error)
       case scala.Right(mailboxValidation) => SMono.fromPublisher(quotas)
-        .map(quotas => scala.Right(
+        .map(quotas =>
           Mailbox(
             id = id,
             name = mailboxValidation.mailboxName,
@@ -152,7 +163,60 @@ class MailboxFactory @Inject() (subscriptionManager: SubscriptionManager) {
             namespace = namespace,
             rights = rights,
             quotas = quotas,
-            isSubscribed = retrieveIsSubscribed)))
+            isSubscribed = isSubscribed))
+    }
+  }
+
+  def create(id: MailboxId, mailboxSession: MailboxSession, quotaLoader: QuotaLoader): SMono[Mailbox] = {
+    try {
+      val messageManager: MessageManager = mailboxManager.getMailbox(id, mailboxSession)
+      val resolvedACL = messageManager.getResolvedAcl(mailboxSession)
+
+      val name: Either[IllegalArgumentException, MailboxName] = retrieveMailboxName(messageManager.getMailboxPath, mailboxSession)
+
+      val role: Option[Role] = getRole(messageManager.getMailboxPath, mailboxSession)
+      val sortOrder: SortOrder = getSortOrder(role)
+      val quotas: SMono[Quotas] = quotaLoader.getQuotas(messageManager.getMailboxPath)
+      val rights: Rights = getRights(resolvedACL)
+
+      val sanitizedCounters: MailboxCounters = messageManager.getMailboxCounters(mailboxSession).sanitize()
+      val unreadEmails: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getUnseen)
+      val unreadThreads: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getUnseen)
+      val totalEmails: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getCount)
+      val totalThreads: Either[NumberFormatException, UnsignedInt] = UnsignedInt.validate(sanitizedCounters.getCount)
+
+      val namespace: MailboxNamespace = getNamespace(messageManager.getMailboxPath, mailboxSession)
+
+      val parentId: Option[MailboxId] = getParentPath(messageManager.getMailboxPath, mailboxSession)
+        .map(parentPath => mailboxManager.getMailbox(parentPath, mailboxSession))
+        .map(_.getId)
+
+      val myRights: MailboxRights = getMyRights(messageManager.getMailboxPath, resolvedACL, mailboxSession)
+
+      val isSubscribed: IsSubscribed = retrieveIsSubscribed(messageManager.getMailboxPath, mailboxSession)
+
+      MailboxValidation.validate(name, unreadEmails, unreadThreads, totalEmails, totalThreads) match {
+        case Left(error) => SMono.raiseError(error)
+        case scala.Right(mailboxValidation) => SMono.fromPublisher(quotas)
+          .map(quotas =>
+            Mailbox(
+              id = id,
+              name = mailboxValidation.mailboxName,
+              parentId = parentId,
+              role = role,
+              sortOrder = sortOrder,
+              unreadEmails = mailboxValidation.unreadEmails,
+              totalEmails = mailboxValidation.totalEmails,
+              unreadThreads = mailboxValidation.unreadThreads,
+              totalThreads = mailboxValidation.totalThreads,
+              myRights = myRights,
+              namespace = namespace,
+              rights = rights,
+              quotas = quotas,
+              isSubscribed = isSubscribed))
+      }
+    } catch {
+      case error: Exception => SMono.raiseError(error)
     }
   }
 }
\ No newline at end of file
diff --git a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
index 2449d6c..b27f06b 100644
--- a/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
+++ b/server/protocols/jmap-rfc-8621/src/test/scala/org/apache/james/jmap/json/MailboxGetSerializationTest.scala
@@ -156,7 +156,7 @@ class MailboxGetSerializationTest extends AnyWordSpec with Matchers {
         accountId = ACCOUNT_ID,
         state = "75128aab4b1b",
         list = List(MAILBOX),
-        notFound = NotFound(List(MAILBOX_ID_1, MAILBOX_ID_2)))
+        notFound = NotFound(Set(MAILBOX_ID_1, MAILBOX_ID_2)))
 
       val expectedJson: String =
         """


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org