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 2018/12/14 10:34:32 UTC

[16/18] james-project git commit: MAILBOX-359 The base POJO used in scala serialization should be Event

MAILBOX-359 The base POJO used in scala serialization should be Event

Modify scala serializer accordingly

Also we will write one test class per event type


Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/db3618d7
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/db3618d7
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/db3618d7

Branch: refs/heads/master
Commit: db3618d7c927c77f92a2798403ededb4c8283823
Parents: ffd767a
Author: Benoit Tellier <bt...@linagora.com>
Authored: Thu Dec 13 10:54:30 2018 +0700
Committer: Benoit Tellier <bt...@linagora.com>
Committed: Fri Dec 14 17:13:32 2018 +0700

----------------------------------------------------------------------
 .../james/event/json/EventSerializer.scala      | 132 ++++
 .../apache/james/event/json/QuotaEvent.scala    | 135 ----
 .../apache/james/event/json/QuotaEventTest.java | 760 -------------------
 ...QuotaUsageUpdatedEventSerializationTest.java | 760 +++++++++++++++++++
 4 files changed, 892 insertions(+), 895 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/db3618d7/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
----------------------------------------------------------------------
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
new file mode 100644
index 0000000..062bea2
--- /dev/null
+++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/EventSerializer.scala
@@ -0,0 +1,132 @@
+/** **************************************************************
+  * Licensed to the Apache Software Foundation (ASF) under one   *
+  * or more contributor license agreements.  See the NOTICE file *
+  * distributed with this work for additional information        *
+  * regarding copyright ownership.  The ASF licenses this file   *
+  * to you under the Apache License, Version 2.0 (the            *
+  * "License"); you may not use this file except in compliance   *
+  * with the License.  You may obtain a copy of the License at   *
+  * *
+  * http://www.apache.org/licenses/LICENSE-2.0                 *
+  * *
+  * Unless required by applicable law or agreed to in writing,   *
+  * software distributed under the License is distributed on an  *
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+  * KIND, either express or implied.  See the License for the    *
+  * specific language governing permissions and limitations      *
+  * under the License.                                           *
+  * ***************************************************************/
+
+package org.apache.james.event.json
+
+import java.time.Instant
+import java.util.Optional
+
+import julienrf.json.derived
+import org.apache.james.core.quota.{QuotaCount, QuotaSize, QuotaValue}
+import org.apache.james.core.{Domain, User}
+import org.apache.james.mailbox.MailboxListener.{QuotaEvent => JavaQuotaEvent, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
+import org.apache.james.mailbox.model.{QuotaRoot, Quota => JavaQuota}
+import org.apache.james.mailbox.{Event => JavaEvent}
+import play.api.libs.json._
+
+import scala.collection.JavaConverters._
+
+private sealed trait Event {
+  def toJava: JavaQuotaEvent
+}
+
+private object DTO {
+
+  case class Quota[T <: QuotaValue[T]](used: T, limit: T, limits: Map[JavaQuota.Scope, T]) {
+    def toJava: JavaQuota[T] =
+      JavaQuota.builder[T]
+        .used(used)
+        .computedLimit(limit)
+        .limitsByScope(limits.asJava)
+        .build()
+  }
+
+  case class QuotaUsageUpdatedEvent(user: User, quotaRoot: QuotaRoot, countQuota: Quota[QuotaCount],
+                                    sizeQuota: Quota[QuotaSize], time: Instant) extends Event {
+    def getQuotaRoot: QuotaRoot = quotaRoot
+
+    override def toJava: JavaQuotaEvent =
+      new JavaQuotaUsageUpdatedEvent(user, getQuotaRoot, countQuota.toJava, sizeQuota.toJava, time)
+  }
+}
+
+private object JsonSerialize {
+  implicit val userWriters: Writes[User] = (user: User) => JsString(user.asString)
+  implicit val quotaRootWrites: Writes[QuotaRoot] = quotaRoot => JsString(quotaRoot.getValue)
+  implicit val quotaValueWrites: Writes[QuotaValue[_]] = value => if (value.isUnlimited) JsNull else JsNumber(value.asLong())
+  implicit val quotaScopeWrites: Writes[JavaQuota.Scope] = value => JsString(value.name)
+  implicit val quotaCountWrites: Writes[DTO.Quota[QuotaCount]] = Json.writes[DTO.Quota[QuotaCount]]
+  implicit val quotaSizeWrites: Writes[DTO.Quota[QuotaSize]] = Json.writes[DTO.Quota[QuotaSize]]
+
+  implicit val userReads: Reads[User] = {
+    case JsString(userAsString) => JsSuccess(User.fromUsername(userAsString))
+    case _ => JsError()
+  }
+  implicit val quotaRootReads: Reads[QuotaRoot] = {
+    case JsString(quotaRoot) => JsSuccess(QuotaRoot.quotaRoot(quotaRoot, Optional.empty[Domain]))
+    case _ => JsError()
+  }
+  implicit val quotaCountReads: Reads[QuotaCount] = {
+    case JsNumber(count) => JsSuccess(QuotaCount.count(count.toLong))
+    case JsNull => JsSuccess(QuotaCount.unlimited())
+    case _ => JsError()
+  }
+  implicit val quotaSizeReads: Reads[QuotaSize] = {
+    case JsNumber(size) => JsSuccess(QuotaSize.size(size.toLong))
+    case JsNull => JsSuccess(QuotaSize.unlimited())
+    case _ => JsError()
+  }
+  implicit val quotaScopeReads: Reads[JavaQuota.Scope] = {
+    case JsString(value) => JsSuccess(JavaQuota.Scope.valueOf(value))
+    case _ => JsError()
+  }
+
+  implicit def scopeMapReads[V](implicit vr: Reads[V]): Reads[Map[JavaQuota.Scope, V]] =
+    Reads.mapReads[JavaQuota.Scope, V] { str =>
+      Json.fromJson[JavaQuota.Scope](JsString(str))
+    }
+
+  implicit def scopeMapWrite[V](implicit vr: Writes[V]): Writes[Map[JavaQuota.Scope, V]] =
+    (m: Map[JavaQuota.Scope, V]) => {
+      JsObject(m.map { case (k, v) => (k.toString, vr.writes(v)) }.toSeq)
+    }
+
+  implicit val quotaCReads: Reads[DTO.Quota[QuotaCount]] = Json.reads[DTO.Quota[QuotaCount]]
+  implicit val quotaSReads: Reads[DTO.Quota[QuotaSize]] = Json.reads[DTO.Quota[QuotaSize]]
+
+  implicit val quotaEventOFormat: OFormat[Event] = derived.oformat()
+
+  def toJson(event: Event): String = Json.toJson(event).toString()
+
+  def fromJson(json: String): JsResult[Event] = Json.fromJson[Event](Json.parse(json))
+}
+
+object EventSerializer {
+
+  private def toScala[T <: QuotaValue[T]](java: JavaQuota[T]): DTO.Quota[T] =
+    DTO.Quota(used = java.getUsed, limit = java.getLimit, limits = java.getLimitByScope.asScala.toMap)
+
+  private def toScala(event: JavaQuotaUsageUpdatedEvent): DTO.QuotaUsageUpdatedEvent =
+    DTO.QuotaUsageUpdatedEvent(
+      user = event.getUser,
+      quotaRoot = event.getQuotaRoot,
+      countQuota = toScala(event.getCountQuota),
+      sizeQuota = toScala(event.getSizeQuota),
+      time = event.getInstant)
+
+  def toJson(event: JavaEvent): String = event match {
+    case e: JavaQuotaUsageUpdatedEvent => JsonSerialize.toJson(toScala(e))
+    case _ => throw new RuntimeException("no encoder found")
+  }
+
+  def fromJson(json: String): JsResult[JavaEvent] = {
+    JsonSerialize.fromJson(json)
+      .map(event => event.toJava)
+  }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/db3618d7/mailbox/event/json/src/main/scala/org/apache/james/event/json/QuotaEvent.scala
----------------------------------------------------------------------
diff --git a/mailbox/event/json/src/main/scala/org/apache/james/event/json/QuotaEvent.scala b/mailbox/event/json/src/main/scala/org/apache/james/event/json/QuotaEvent.scala
deleted file mode 100644
index 26be6d6..0000000
--- a/mailbox/event/json/src/main/scala/org/apache/james/event/json/QuotaEvent.scala
+++ /dev/null
@@ -1,135 +0,0 @@
-/** **************************************************************
-  * Licensed to the Apache Software Foundation (ASF) under one   *
-  * or more contributor license agreements.  See the NOTICE file *
-  * distributed with this work for additional information        *
-  * regarding copyright ownership.  The ASF licenses this file   *
-  * to you under the Apache License, Version 2.0 (the            *
-  * "License"); you may not use this file except in compliance   *
-  * with the License.  You may obtain a copy of the License at   *
-  * *
-  * http://www.apache.org/licenses/LICENSE-2.0                 *
-  * *
-  * Unless required by applicable law or agreed to in writing,   *
-  * software distributed under the License is distributed on an  *
-  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
-  * KIND, either express or implied.  See the License for the    *
-  * specific language governing permissions and limitations      *
-  * under the License.                                           *
-  * ***************************************************************/
-
-package org.apache.james.event.json
-
-import java.time.Instant
-import java.util.Optional
-
-import julienrf.json.derived
-import org.apache.james.core.quota.{QuotaCount, QuotaSize, QuotaValue}
-import org.apache.james.core.{Domain, User}
-import org.apache.james.mailbox.MailboxListener.{QuotaEvent => JavaQuotaEvent, QuotaUsageUpdatedEvent => JavaQuotaUsageUpdatedEvent}
-import org.apache.james.mailbox.model.{QuotaRoot, Quota => JavaQuota}
-import play.api.libs.json.{JsError, JsNull, JsNumber, JsObject, JsResult, JsString, JsSuccess, Json, OFormat, Reads, Writes}
-
-import scala.collection.JavaConverters._
-import scala.compat.java8.OptionConverters
-
-private sealed trait QuotaEvent {
-  def getQuotaRoot: QuotaRoot
-
-  def toJava: JavaQuotaEvent
-}
-
-private object DTO {
-
-  case class Quota[T <: QuotaValue[T]](used: T, limit: T, limits: Map[JavaQuota.Scope, T]) {
-    def toJava: JavaQuota[T] =
-      JavaQuota.builder[T]
-        .used(used)
-        .computedLimit(limit)
-        .limitsByScope(limits.asJava)
-        .build()
-  }
-
-  case class QuotaUsageUpdatedEvent(user: User, quotaRoot: QuotaRoot, countQuota: Quota[QuotaCount],
-                                    sizeQuota: Quota[QuotaSize], time: Instant) extends QuotaEvent {
-    override def getQuotaRoot: QuotaRoot = quotaRoot
-
-    override def toJava: JavaQuotaEvent =
-      new JavaQuotaUsageUpdatedEvent(user, getQuotaRoot, countQuota.toJava, sizeQuota.toJava, time)
-  }
-
-}
-
-private object JsonSerialize {
-  implicit val userWriters: Writes[User] = (user: User) => JsString(user.asString)
-  implicit val quotaRootWrites: Writes[QuotaRoot] = quotaRoot => JsString(quotaRoot.getValue)
-  implicit val quotaValueWrites: Writes[QuotaValue[_]] = value => if (value.isUnlimited) JsNull else JsNumber(value.asLong())
-  implicit val quotaScopeWrites: Writes[JavaQuota.Scope] = value => JsString(value.name)
-  implicit val quotaCountWrites: Writes[DTO.Quota[QuotaCount]] = Json.writes[DTO.Quota[QuotaCount]]
-  implicit val quotaSizeWrites: Writes[DTO.Quota[QuotaSize]] = Json.writes[DTO.Quota[QuotaSize]]
-
-  implicit val userReads: Reads[User] = {
-    case JsString(userAsString) => JsSuccess(User.fromUsername(userAsString))
-    case _ => JsError()
-  }
-  implicit val quotaRootReads: Reads[QuotaRoot] = {
-    case JsString(quotaRoot) => JsSuccess(QuotaRoot.quotaRoot(quotaRoot, Optional.empty[Domain]))
-    case _ => JsError()
-  }
-  implicit val quotaCountReads: Reads[QuotaCount] = {
-    case JsNumber(count) => JsSuccess(QuotaCount.count(count.toLong))
-    case JsNull => JsSuccess(QuotaCount.unlimited())
-    case _ => JsError()
-  }
-  implicit val quotaSizeReads: Reads[QuotaSize] = {
-    case JsNumber(size) => JsSuccess(QuotaSize.size(size.toLong))
-    case JsNull => JsSuccess(QuotaSize.unlimited())
-    case _ => JsError()
-  }
-  implicit val quotaScopeReads: Reads[JavaQuota.Scope] = {
-    case JsString(value) => JsSuccess(JavaQuota.Scope.valueOf(value))
-    case _ => JsError()
-  }
-
-  implicit def scopeMapReads[V](implicit vr: Reads[V]): Reads[Map[JavaQuota.Scope, V]] =
-    Reads.mapReads[JavaQuota.Scope, V] { str =>
-      Json.fromJson[JavaQuota.Scope](JsString(str))
-    }
-
-  implicit def scopeMapWrite[V](implicit vr: Writes[V]): Writes[Map[JavaQuota.Scope, V]] =
-    (m: Map[JavaQuota.Scope, V]) => {
-      JsObject(m.map { case (k, v) => (k.toString, vr.writes(v)) }.toSeq)
-    }
-
-  implicit val quotaCReads: Reads[DTO.Quota[QuotaCount]] = Json.reads[DTO.Quota[QuotaCount]]
-  implicit val quotaSReads: Reads[DTO.Quota[QuotaSize]] = Json.reads[DTO.Quota[QuotaSize]]
-
-  implicit val quotaEventOFormat: OFormat[QuotaEvent] = derived.oformat()
-
-  def toJson(event: QuotaEvent): String = Json.toJson(event).toString()
-
-  def fromJson(json: String): JsResult[QuotaEvent] = Json.fromJson[QuotaEvent](Json.parse(json))
-}
-
-object QuotaEvent {
-
-  private def toScala[T <: QuotaValue[T]](java: JavaQuota[T]): DTO.Quota[T] =
-    DTO.Quota(used = java.getUsed, limit = java.getLimit, limits = java.getLimitByScope.asScala.toMap)
-
-  private def toScala(event: JavaQuotaUsageUpdatedEvent): DTO.QuotaUsageUpdatedEvent =
-    DTO.QuotaUsageUpdatedEvent(
-      user = event.getUser,
-      quotaRoot = event.getQuotaRoot,
-      countQuota = toScala(event.getCountQuota),
-      sizeQuota = toScala(event.getSizeQuota),
-      time = event.getInstant)
-
-  def toJson(event: JavaQuotaEvent): String = event match {
-    case e: JavaQuotaUsageUpdatedEvent => JsonSerialize.toJson(toScala(e))
-    case _ => throw new RuntimeException("no encoder found")
-  }
-
-  def fromJson(json: String): JsResult[JavaQuotaEvent] = {
-    JsonSerialize.fromJson(json)
-      .map(event => event.toJava)
-  }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/db3618d7/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaEventTest.java
----------------------------------------------------------------------
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaEventTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaEventTest.java
deleted file mode 100644
index 9dc3a04..0000000
--- a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaEventTest.java
+++ /dev/null
@@ -1,760 +0,0 @@
-/****************************************************************
- * Licensed to the Apache Software Foundation (ASF) under one   *
- * or more contributor license agreements.  See the NOTICE file *
- * distributed with this work for additional information        *
- * regarding copyright ownership.  The ASF licenses this file   *
- * to you under the Apache License, Version 2.0 (the            *
- * "License"); you may not use this file except in compliance   *
- * with the License.  You may obtain a copy of the License at   *
- *                                                              *
- *   http://www.apache.org/licenses/LICENSE-2.0                 *
- *                                                              *
- * Unless required by applicable law or agreed to in writing,   *
- * software distributed under the License is distributed on an  *
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
- * KIND, either express or implied.  See the License for the    *
- * specific language governing permissions and limitations      *
- * under the License.                                           *
- ****************************************************************/
-
-package org.apache.james.event.json;
-
-import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
-
-import java.time.Instant;
-import java.util.NoSuchElementException;
-import java.util.Optional;
-
-import org.apache.james.core.User;
-import org.apache.james.core.quota.QuotaCount;
-import org.apache.james.core.quota.QuotaSize;
-import org.apache.james.mailbox.MailboxListener;
-import org.apache.james.mailbox.model.Quota;
-import org.apache.james.mailbox.model.QuotaRoot;
-import org.junit.jupiter.api.Nested;
-import org.junit.jupiter.api.Test;
-
-class QuotaEventTest {
-
-    private static final User USER = User.fromUsername("user");
-    private static final QuotaRoot QUOTA_ROOT = QuotaRoot.quotaRoot("foo", Optional.empty());
-    private static final Quota<QuotaCount> QUOTA_COUNT = Quota.<QuotaCount>builder()
-        .used(QuotaCount.count(12))
-        .computedLimit(QuotaCount.count(100))
-        .build();
-    private static final Quota<QuotaSize> QUOTA_SIZE = Quota.<QuotaSize>builder()
-        .used(QuotaSize.size(1234))
-        .computedLimit(QuotaSize.size(10000))
-        .build();
-    private static final Instant INSTANT = Instant.parse("2018-11-13T12:00:55Z");
-    private static final MailboxListener.QuotaUsageUpdatedEvent DEFAULT_QUOTA_EVENT =
-        new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, QUOTA_COUNT, QUOTA_SIZE, INSTANT);
-
-    private static final String DEFAULT_QUOTA_EVENT_JSON =
-        "{" +
-            "\"QuotaUsageUpdatedEvent\":{" +
-            "\"quotaRoot\":\"foo\"," +
-            "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-            "\"time\":\"2018-11-13T12:00:55Z\"," +
-            "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-            "\"user\":\"user\"" +
-            "}" +
-        "}";
-
-    private static final QuotaEvent$ QUOTA_EVENT_MODULE = QuotaEvent$.MODULE$;
-
-    @Nested
-    class WithUser {
-
-        @Nested
-        class WithValidUser {
-
-            @Nested
-            class WithUserContainsOnlyUsername {
-
-                private final MailboxListener.QuotaUsageUpdatedEvent eventWithUserContainsUsername = new MailboxListener.QuotaUsageUpdatedEvent(
-                    User.fromUsername("onlyUsername"),
-                    QUOTA_ROOT,
-                    QUOTA_COUNT,
-                    QUOTA_SIZE,
-                    INSTANT);
-                private final String quotaUsageUpdatedEvent =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"onlyUsername\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void fromJsonShouldReturnQuotaEvent() {
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                        .isEqualTo(eventWithUserContainsUsername);
-                }
-
-                @Test
-                void toJsonShouldReturnQuotaEventJson() {
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithUserContainsUsername))
-                        .isEqualTo(quotaUsageUpdatedEvent);
-                }
-            }
-
-            @Nested
-            class WithUserContainsUsernameAndDomain {
-
-                private final MailboxListener.QuotaUsageUpdatedEvent eventWithUserContainsUsernameAndDomain = new MailboxListener.QuotaUsageUpdatedEvent(
-                    User.fromUsername("user@domain"),
-                    QUOTA_ROOT,
-                    QUOTA_COUNT,
-                    QUOTA_SIZE,
-                    INSTANT);
-                private final String quotaUsageUpdatedEvent =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user@domain\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void fromJsonShouldReturnQuotaEvent() {
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                        .isEqualTo(eventWithUserContainsUsernameAndDomain);
-                }
-
-                @Test
-                void toJsonShouldReturnQuotaEventJson() {
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithUserContainsUsernameAndDomain))
-                        .isEqualTo(quotaUsageUpdatedEvent);
-                }
-            }
-        }
-
-        @Nested
-        class WithInvalidUser {
-
-            @Test
-            void fromJsonShouldThrowWhenEmptyUser() {
-                String quotaUsageUpdatedEvent =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"\"" +
-                        "}" +
-                    "}";
-                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent))
-                    .isInstanceOf(IllegalArgumentException.class);
-            }
-
-
-            @Test
-            void fromJsonShouldThrowResultWhenUserIsNull() {
-                String quotaUsageUpdatedEvent =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}" +
-                        "}" +
-                    "}";
-
-                assertThatThrownBy(() ->QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                    .isInstanceOf(NoSuchElementException.class);
-            }
-
-            @Test
-            void fromJsonShouldThrowWhenUserIsInvalid() {
-                String quotaUsageUpdatedEvent =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"@domain\"" +
-                        "}" +
-                    "}";
-                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent))
-                    .isInstanceOf(IllegalArgumentException.class);
-            }
-        }
-
-    }
-
-    @Nested
-    class WitQuotaRoot {
-
-        @Nested
-        class WithNormalQuotaRoot {
-
-            @Test
-            void toJsonShouldReturnSerializedJsonQuotaRoot() {
-                assertThatJson(QUOTA_EVENT_MODULE.toJson(DEFAULT_QUOTA_EVENT))
-                    .isEqualTo(DEFAULT_QUOTA_EVENT_JSON);
-            }
-
-            @Test
-            void fromJsonShouldDeserializeQuotaRootJson() {
-                assertThat(QUOTA_EVENT_MODULE.fromJson(DEFAULT_QUOTA_EVENT_JSON).get())
-                    .isEqualTo(DEFAULT_QUOTA_EVENT);
-            }
-        }
-
-        @Nested
-        class WithEmptyQuotaRoot {
-            private final QuotaRoot emptyQuotaRoot = QuotaRoot.quotaRoot("", Optional.empty());
-            private final MailboxListener.QuotaUsageUpdatedEvent eventWithEmptyQuotaRoot =
-                new MailboxListener.QuotaUsageUpdatedEvent(
-                    USER,
-                    emptyQuotaRoot,
-                    QUOTA_COUNT,
-                    QUOTA_SIZE,
-                    INSTANT);
-            private final String quotaUsageUpdatedEvent =
-                "{" +
-                    "\"QuotaUsageUpdatedEvent\":{" +
-                    "\"quotaRoot\":\"\"," +
-                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                    "\"time\":\"2018-11-13T12:00:55Z\"," +
-                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                    "\"user\":\"user\"" +
-                    "}" +
-                "}";
-
-            @Test
-            void toJsonShouldSerializeWithEmptyQuotaRoot() {
-                assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithEmptyQuotaRoot))
-                    .isEqualTo(quotaUsageUpdatedEvent);
-            }
-
-            @Test
-            void fromJsonShouldDeserializeWithEmptyQuotaRoot() {
-                assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                    .isEqualTo(eventWithEmptyQuotaRoot);
-            }
-        }
-
-        @Nested
-        class WithNullQuotaRoot {
-            private final MailboxListener.QuotaUsageUpdatedEvent eventWithNullQuotaRoot =
-                new MailboxListener.QuotaUsageUpdatedEvent(
-                    USER,
-                    null,
-                    QUOTA_COUNT,
-                    QUOTA_SIZE,
-                    INSTANT);
-
-            private final String quotaUsageUpdatedEvent =
-                "{" +
-                    "\"QuotaUsageUpdatedEvent\":{" +
-                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                    "\"time\":\"2018-11-13T12:00:55Z\"," +
-                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                    "\"user\":\"user\"" +
-                    "}" +
-                "}";
-
-            @Test
-            void toJsonShouldThrowWithNullQuotaRoot() {
-                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.toJson(eventWithNullQuotaRoot))
-                    .isInstanceOf(NullPointerException.class);
-            }
-
-            @Test
-            void fromJsonShouldThrowWithNullQuotaRoot() {
-                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                    .isInstanceOf(NoSuchElementException.class);
-            }
-        }
-    }
-
-    
-    @Nested
-    class WithQuotaCount {
-
-        private MailboxListener.QuotaUsageUpdatedEvent quotaEventByQuotaCount(Quota<QuotaCount> countQuota) {
-            return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, countQuota, QUOTA_SIZE, INSTANT);
-        }
-
-        @Nested
-        class LimitedQuotaCount {
-
-            private Quota<QuotaCount> limitedQuotaCountByScopes(Quota.Scope scope) {
-                return Quota.<QuotaCount>builder()
-                    .used(QuotaCount.count(12))
-                    .computedLimit(QuotaCount.count(100))
-                    .limitForScope(QuotaCount.count(100), scope)
-                    .build();
-            }
-
-            @Nested
-            class LimitedQuotaGlobalScope {
-
-                private final String limitedQuotaCountEventJsonGlobalScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Global\":100}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Global));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaCountEventJsonGlobalScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Global));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonGlobalScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class LimitedQuotaDomainScope {
-                private final String limitedQuotaCountEventJsonDomainScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Domain));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaCountEventJsonDomainScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Domain));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonDomainScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class LimitedQuotaUserScope {
-                private final String limitedQuotaCountEventJsonUserScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"User\":100}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.User));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaCountEventJsonUserScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.User));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonUserScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-        }
-
-        @Nested
-        class UnLimitedQuotaCount {
-
-            private Quota<QuotaCount> unLimitedQuotaCountByScopes(Quota.Scope scope) {
-                return Quota.<QuotaCount>builder()
-                    .used(QuotaCount.count(12))
-                    .computedLimit(QuotaCount.unlimited())
-                    .limitForScope(QuotaCount.unlimited(), scope)
-                    .build();
-            }
-
-            @Nested
-            class UnLimitedQuotaGlobalScope {
-                private final String unLimitedQuotaCountEventJsonGlobalScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"Global\":null}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Global));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaCountEventJsonGlobalScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Global));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonGlobalScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class UnLimitedQuotaDomainScope {
-                private final String unLimitedQuotaCountEventJsonDomainScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"Domain\":null}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Domain));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaCountEventJsonDomainScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Domain));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonDomainScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class UnLimitedQuotaUserScope {
-                private final String unLimitedQuotaCountEventJsonUserScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"User\":null}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.User));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaCountEventJsonUserScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaCount() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.User));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonUserScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-        }
-    }
-
-    
-    @Nested
-    class WithQuotaSize {
-
-        private MailboxListener.QuotaUsageUpdatedEvent quotaEventByQuotaSize(Quota<QuotaSize> quotaSize) {
-            return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, QUOTA_COUNT, quotaSize, INSTANT);
-        }
-
-        @Nested
-        class LimitedQuotaSize {
-
-            private Quota<QuotaSize> limitedQuotaSizeByScopes(Quota.Scope scope) {
-                return Quota.<QuotaSize>builder()
-                    .used(QuotaSize.size(1234))
-                    .computedLimit(QuotaSize.size(10000))
-                    .limitForScope(QuotaSize.size(10000), scope)
-                    .build();
-            }
-
-            @Nested
-            class LimitedQuotaSizeGlobalScope {
-
-                private final String limitedQuotaSizeEventJsonGlobalScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"Global\":10000}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Global));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaSizeEventJsonGlobalScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Global));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonGlobalScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class LimitedQuotaSizeDomainScope {
-                private final String limitedQuotaSizeEventJsonDomainScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"Domain\":10000}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Domain));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaSizeEventJsonDomainScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Domain));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonDomainScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class LimitedQuotaSizeUserScope {
-                private final String limitedQuotaSizeEventJsonUserScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"User\":10000}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.User));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(limitedQuotaSizeEventJsonUserScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.User));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonUserScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-        }
-
-        @Nested
-        class UnLimitedQuotaSize {
-
-            private Quota<QuotaSize> unLimitedQuotaSizeByScopes(Quota.Scope scope) {
-                return Quota.<QuotaSize>builder()
-                    .used(QuotaSize.size(1234))
-                    .computedLimit(QuotaSize.unlimited())
-                    .limitForScope(QuotaSize.unlimited(), scope)
-                    .build();
-            }
-
-            @Nested
-            class UnLimitedQuotaSizeGlobalScope {
-
-                private final String unLimitedQuotaSizeEventJsonGlobalScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"Global\":null}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Global));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaSizeEventJsonGlobalScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Global));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonGlobalScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class UnLimitedQuotaSizeDomainScope {
-                private final String unLimitedQuotaSizeEventJsonDomainScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"Domain\":null}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Domain));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaSizeEventJsonDomainScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Domain));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonDomainScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-
-            @Nested
-            class UnLimitedQuotaSizeUserScope {
-                private final String unLimitedQuotaSizeEventJsonUserScope =
-                    "{" +
-                        "\"QuotaUsageUpdatedEvent\":{" +
-                        "\"quotaRoot\":\"foo\"," +
-                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
-                        "\"time\":\"2018-11-13T12:00:55Z\"," +
-                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"User\":null}}," +
-                        "\"user\":\"user\"" +
-                        "}" +
-                    "}";
-
-                @Test
-                void toJsonShouldSerializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.User));
-
-                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
-                        .isEqualTo(unLimitedQuotaSizeEventJsonUserScope);
-                }
-
-                @Test
-                void fromJsonShouldDeserializeQuotaSize() {
-                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.User));
-
-                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonUserScope).get())
-                        .isEqualTo(quotaEvent);
-                }
-            }
-        }
-    }
-
-    @Nested
-    class WithTime {
-
-        @Test
-        void toJsonShouldReturnSerializedJsonEventWhenTimeIsValid() {
-            assertThatJson(QUOTA_EVENT_MODULE.toJson(DEFAULT_QUOTA_EVENT))
-                .isEqualTo(DEFAULT_QUOTA_EVENT_JSON);
-        }
-
-        @Test
-        void fromJsonShouldReturnDeSerializedEventWhenTimeIsValid() {
-            assertThat(QUOTA_EVENT_MODULE.fromJson(DEFAULT_QUOTA_EVENT_JSON).get())
-                .isEqualTo(DEFAULT_QUOTA_EVENT);
-        }
-
-        @Test
-        void fromJsonShouldThrowResultWhenTimeIsNull() {
-            String quotaUsageUpdatedEvent =
-                "{" +
-                    "\"QuotaUsageUpdatedEvent\":{" +
-                    "\"quotaRoot\":\"foo\"," +
-                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
-                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                    "\"user\":\"user\"" +
-                    "}" +
-                "}";
-
-            assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                .isInstanceOf(NoSuchElementException.class);
-        }
-
-        @Test
-        void fromJsonShouldThrowResultWhenTimeIsEmpty() {
-            String quotaUsageUpdatedEvent =
-                "{" +
-                    "\"QuotaUsageUpdatedEvent\":{" +
-                    "\"quotaRoot\":\"foo\"," +
-                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
-                    "\"time\":\"\"," +
-                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
-                    "\"user\":\"user\"" +
-                    "}" +
-                "}";
-
-            assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
-                .isInstanceOf(NoSuchElementException.class);
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/db3618d7/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
----------------------------------------------------------------------
diff --git a/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
new file mode 100644
index 0000000..0a55edc
--- /dev/null
+++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaUsageUpdatedEventSerializationTest.java
@@ -0,0 +1,760 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.event.json;
+
+import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import java.time.Instant;
+import java.util.NoSuchElementException;
+import java.util.Optional;
+
+import org.apache.james.core.User;
+import org.apache.james.core.quota.QuotaCount;
+import org.apache.james.core.quota.QuotaSize;
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.model.QuotaRoot;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class QuotaUsageUpdatedEventSerializationTest {
+
+    private static final User USER = User.fromUsername("user");
+    private static final QuotaRoot QUOTA_ROOT = QuotaRoot.quotaRoot("foo", Optional.empty());
+    private static final Quota<QuotaCount> QUOTA_COUNT = Quota.<QuotaCount>builder()
+        .used(QuotaCount.count(12))
+        .computedLimit(QuotaCount.count(100))
+        .build();
+    private static final Quota<QuotaSize> QUOTA_SIZE = Quota.<QuotaSize>builder()
+        .used(QuotaSize.size(1234))
+        .computedLimit(QuotaSize.size(10000))
+        .build();
+    private static final Instant INSTANT = Instant.parse("2018-11-13T12:00:55Z");
+    private static final MailboxListener.QuotaUsageUpdatedEvent DEFAULT_QUOTA_EVENT =
+        new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, QUOTA_COUNT, QUOTA_SIZE, INSTANT);
+
+    private static final String DEFAULT_QUOTA_EVENT_JSON =
+        "{" +
+            "\"QuotaUsageUpdatedEvent\":{" +
+            "\"quotaRoot\":\"foo\"," +
+            "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+            "\"time\":\"2018-11-13T12:00:55Z\"," +
+            "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+            "\"user\":\"user\"" +
+            "}" +
+        "}";
+
+    private static final EventSerializer$ QUOTA_EVENT_MODULE = EventSerializer$.MODULE$;
+
+    @Nested
+    class WithUser {
+
+        @Nested
+        class WithValidUser {
+
+            @Nested
+            class WithUserContainsOnlyUsername {
+
+                private final MailboxListener.QuotaUsageUpdatedEvent eventWithUserContainsUsername = new MailboxListener.QuotaUsageUpdatedEvent(
+                    User.fromUsername("onlyUsername"),
+                    QUOTA_ROOT,
+                    QUOTA_COUNT,
+                    QUOTA_SIZE,
+                    INSTANT);
+                private final String quotaUsageUpdatedEvent =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"onlyUsername\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void fromJsonShouldReturnQuotaEvent() {
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                        .isEqualTo(eventWithUserContainsUsername);
+                }
+
+                @Test
+                void toJsonShouldReturnQuotaEventJson() {
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithUserContainsUsername))
+                        .isEqualTo(quotaUsageUpdatedEvent);
+                }
+            }
+
+            @Nested
+            class WithUserContainsUsernameAndDomain {
+
+                private final MailboxListener.QuotaUsageUpdatedEvent eventWithUserContainsUsernameAndDomain = new MailboxListener.QuotaUsageUpdatedEvent(
+                    User.fromUsername("user@domain"),
+                    QUOTA_ROOT,
+                    QUOTA_COUNT,
+                    QUOTA_SIZE,
+                    INSTANT);
+                private final String quotaUsageUpdatedEvent =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user@domain\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void fromJsonShouldReturnQuotaEvent() {
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                        .isEqualTo(eventWithUserContainsUsernameAndDomain);
+                }
+
+                @Test
+                void toJsonShouldReturnQuotaEventJson() {
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithUserContainsUsernameAndDomain))
+                        .isEqualTo(quotaUsageUpdatedEvent);
+                }
+            }
+        }
+
+        @Nested
+        class WithInvalidUser {
+
+            @Test
+            void fromJsonShouldThrowWhenEmptyUser() {
+                String quotaUsageUpdatedEvent =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"\"" +
+                        "}" +
+                    "}";
+                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent))
+                    .isInstanceOf(IllegalArgumentException.class);
+            }
+
+
+            @Test
+            void fromJsonShouldThrowResultWhenUserIsNull() {
+                String quotaUsageUpdatedEvent =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}" +
+                        "}" +
+                    "}";
+
+                assertThatThrownBy(() ->QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                    .isInstanceOf(NoSuchElementException.class);
+            }
+
+            @Test
+            void fromJsonShouldThrowWhenUserIsInvalid() {
+                String quotaUsageUpdatedEvent =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"@domain\"" +
+                        "}" +
+                    "}";
+                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent))
+                    .isInstanceOf(IllegalArgumentException.class);
+            }
+        }
+
+    }
+
+    @Nested
+    class WitQuotaRoot {
+
+        @Nested
+        class WithNormalQuotaRoot {
+
+            @Test
+            void toJsonShouldReturnSerializedJsonQuotaRoot() {
+                assertThatJson(QUOTA_EVENT_MODULE.toJson(DEFAULT_QUOTA_EVENT))
+                    .isEqualTo(DEFAULT_QUOTA_EVENT_JSON);
+            }
+
+            @Test
+            void fromJsonShouldDeserializeQuotaRootJson() {
+                assertThat(QUOTA_EVENT_MODULE.fromJson(DEFAULT_QUOTA_EVENT_JSON).get())
+                    .isEqualTo(DEFAULT_QUOTA_EVENT);
+            }
+        }
+
+        @Nested
+        class WithEmptyQuotaRoot {
+            private final QuotaRoot emptyQuotaRoot = QuotaRoot.quotaRoot("", Optional.empty());
+            private final MailboxListener.QuotaUsageUpdatedEvent eventWithEmptyQuotaRoot =
+                new MailboxListener.QuotaUsageUpdatedEvent(
+                    USER,
+                    emptyQuotaRoot,
+                    QUOTA_COUNT,
+                    QUOTA_SIZE,
+                    INSTANT);
+            private final String quotaUsageUpdatedEvent =
+                "{" +
+                    "\"QuotaUsageUpdatedEvent\":{" +
+                    "\"quotaRoot\":\"\"," +
+                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                    "\"time\":\"2018-11-13T12:00:55Z\"," +
+                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                    "\"user\":\"user\"" +
+                    "}" +
+                "}";
+
+            @Test
+            void toJsonShouldSerializeWithEmptyQuotaRoot() {
+                assertThatJson(QUOTA_EVENT_MODULE.toJson(eventWithEmptyQuotaRoot))
+                    .isEqualTo(quotaUsageUpdatedEvent);
+            }
+
+            @Test
+            void fromJsonShouldDeserializeWithEmptyQuotaRoot() {
+                assertThat(QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                    .isEqualTo(eventWithEmptyQuotaRoot);
+            }
+        }
+
+        @Nested
+        class WithNullQuotaRoot {
+            private final MailboxListener.QuotaUsageUpdatedEvent eventWithNullQuotaRoot =
+                new MailboxListener.QuotaUsageUpdatedEvent(
+                    USER,
+                    null,
+                    QUOTA_COUNT,
+                    QUOTA_SIZE,
+                    INSTANT);
+
+            private final String quotaUsageUpdatedEvent =
+                "{" +
+                    "\"QuotaUsageUpdatedEvent\":{" +
+                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                    "\"time\":\"2018-11-13T12:00:55Z\"," +
+                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                    "\"user\":\"user\"" +
+                    "}" +
+                "}";
+
+            @Test
+            void toJsonShouldThrowWithNullQuotaRoot() {
+                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.toJson(eventWithNullQuotaRoot))
+                    .isInstanceOf(NullPointerException.class);
+            }
+
+            @Test
+            void fromJsonShouldThrowWithNullQuotaRoot() {
+                assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                    .isInstanceOf(NoSuchElementException.class);
+            }
+        }
+    }
+
+    
+    @Nested
+    class WithQuotaCount {
+
+        private MailboxListener.QuotaUsageUpdatedEvent quotaEventByQuotaCount(Quota<QuotaCount> countQuota) {
+            return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, countQuota, QUOTA_SIZE, INSTANT);
+        }
+
+        @Nested
+        class LimitedQuotaCount {
+
+            private Quota<QuotaCount> limitedQuotaCountByScopes(Quota.Scope scope) {
+                return Quota.<QuotaCount>builder()
+                    .used(QuotaCount.count(12))
+                    .computedLimit(QuotaCount.count(100))
+                    .limitForScope(QuotaCount.count(100), scope)
+                    .build();
+            }
+
+            @Nested
+            class LimitedQuotaGlobalScope {
+
+                private final String limitedQuotaCountEventJsonGlobalScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Global\":100}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Global));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaCountEventJsonGlobalScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Global));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonGlobalScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class LimitedQuotaDomainScope {
+                private final String limitedQuotaCountEventJsonDomainScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Domain));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaCountEventJsonDomainScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.Domain));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonDomainScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class LimitedQuotaUserScope {
+                private final String limitedQuotaCountEventJsonUserScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"User\":100}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.User));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaCountEventJsonUserScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(limitedQuotaCountByScopes(Quota.Scope.User));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaCountEventJsonUserScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+        }
+
+        @Nested
+        class UnLimitedQuotaCount {
+
+            private Quota<QuotaCount> unLimitedQuotaCountByScopes(Quota.Scope scope) {
+                return Quota.<QuotaCount>builder()
+                    .used(QuotaCount.count(12))
+                    .computedLimit(QuotaCount.unlimited())
+                    .limitForScope(QuotaCount.unlimited(), scope)
+                    .build();
+            }
+
+            @Nested
+            class UnLimitedQuotaGlobalScope {
+                private final String unLimitedQuotaCountEventJsonGlobalScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"Global\":null}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Global));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaCountEventJsonGlobalScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Global));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonGlobalScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class UnLimitedQuotaDomainScope {
+                private final String unLimitedQuotaCountEventJsonDomainScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"Domain\":null}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Domain));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaCountEventJsonDomainScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.Domain));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonDomainScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class UnLimitedQuotaUserScope {
+                private final String unLimitedQuotaCountEventJsonUserScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":null,\"limits\":{\"User\":null}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.User));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaCountEventJsonUserScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaCount() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaCount(unLimitedQuotaCountByScopes(Quota.Scope.User));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaCountEventJsonUserScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+        }
+    }
+
+    
+    @Nested
+    class WithQuotaSize {
+
+        private MailboxListener.QuotaUsageUpdatedEvent quotaEventByQuotaSize(Quota<QuotaSize> quotaSize) {
+            return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, QUOTA_COUNT, quotaSize, INSTANT);
+        }
+
+        @Nested
+        class LimitedQuotaSize {
+
+            private Quota<QuotaSize> limitedQuotaSizeByScopes(Quota.Scope scope) {
+                return Quota.<QuotaSize>builder()
+                    .used(QuotaSize.size(1234))
+                    .computedLimit(QuotaSize.size(10000))
+                    .limitForScope(QuotaSize.size(10000), scope)
+                    .build();
+            }
+
+            @Nested
+            class LimitedQuotaSizeGlobalScope {
+
+                private final String limitedQuotaSizeEventJsonGlobalScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"Global\":10000}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Global));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaSizeEventJsonGlobalScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Global));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonGlobalScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class LimitedQuotaSizeDomainScope {
+                private final String limitedQuotaSizeEventJsonDomainScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"Domain\":10000}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Domain));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaSizeEventJsonDomainScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.Domain));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonDomainScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class LimitedQuotaSizeUserScope {
+                private final String limitedQuotaSizeEventJsonUserScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{\"User\":10000}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.User));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(limitedQuotaSizeEventJsonUserScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(limitedQuotaSizeByScopes(Quota.Scope.User));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(limitedQuotaSizeEventJsonUserScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+        }
+
+        @Nested
+        class UnLimitedQuotaSize {
+
+            private Quota<QuotaSize> unLimitedQuotaSizeByScopes(Quota.Scope scope) {
+                return Quota.<QuotaSize>builder()
+                    .used(QuotaSize.size(1234))
+                    .computedLimit(QuotaSize.unlimited())
+                    .limitForScope(QuotaSize.unlimited(), scope)
+                    .build();
+            }
+
+            @Nested
+            class UnLimitedQuotaSizeGlobalScope {
+
+                private final String unLimitedQuotaSizeEventJsonGlobalScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"Global\":null}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Global));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaSizeEventJsonGlobalScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Global));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonGlobalScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class UnLimitedQuotaSizeDomainScope {
+                private final String unLimitedQuotaSizeEventJsonDomainScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"Domain\":null}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Domain));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaSizeEventJsonDomainScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.Domain));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonDomainScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+
+            @Nested
+            class UnLimitedQuotaSizeUserScope {
+                private final String unLimitedQuotaSizeEventJsonUserScope =
+                    "{" +
+                        "\"QuotaUsageUpdatedEvent\":{" +
+                        "\"quotaRoot\":\"foo\"," +
+                        "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{}}," +
+                        "\"time\":\"2018-11-13T12:00:55Z\"," +
+                        "\"sizeQuota\":{\"used\":1234,\"limit\":null,\"limits\":{\"User\":null}}," +
+                        "\"user\":\"user\"" +
+                        "}" +
+                    "}";
+
+                @Test
+                void toJsonShouldSerializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.User));
+
+                    assertThatJson(QUOTA_EVENT_MODULE.toJson(quotaEvent))
+                        .isEqualTo(unLimitedQuotaSizeEventJsonUserScope);
+                }
+
+                @Test
+                void fromJsonShouldDeserializeQuotaSize() {
+                    MailboxListener.QuotaUsageUpdatedEvent quotaEvent = quotaEventByQuotaSize(unLimitedQuotaSizeByScopes(Quota.Scope.User));
+
+                    assertThat(QUOTA_EVENT_MODULE.fromJson(unLimitedQuotaSizeEventJsonUserScope).get())
+                        .isEqualTo(quotaEvent);
+                }
+            }
+        }
+    }
+
+    @Nested
+    class WithTime {
+
+        @Test
+        void toJsonShouldReturnSerializedJsonEventWhenTimeIsValid() {
+            assertThatJson(QUOTA_EVENT_MODULE.toJson(DEFAULT_QUOTA_EVENT))
+                .isEqualTo(DEFAULT_QUOTA_EVENT_JSON);
+        }
+
+        @Test
+        void fromJsonShouldReturnDeSerializedEventWhenTimeIsValid() {
+            assertThat(QUOTA_EVENT_MODULE.fromJson(DEFAULT_QUOTA_EVENT_JSON).get())
+                .isEqualTo(DEFAULT_QUOTA_EVENT);
+        }
+
+        @Test
+        void fromJsonShouldThrowResultWhenTimeIsNull() {
+            String quotaUsageUpdatedEvent =
+                "{" +
+                    "\"QuotaUsageUpdatedEvent\":{" +
+                    "\"quotaRoot\":\"foo\"," +
+                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
+                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                    "\"user\":\"user\"" +
+                    "}" +
+                "}";
+
+            assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                .isInstanceOf(NoSuchElementException.class);
+        }
+
+        @Test
+        void fromJsonShouldThrowResultWhenTimeIsEmpty() {
+            String quotaUsageUpdatedEvent =
+                "{" +
+                    "\"QuotaUsageUpdatedEvent\":{" +
+                    "\"quotaRoot\":\"foo\"," +
+                    "\"countQuota\":{\"used\":12,\"limit\":100,\"limits\":{\"Domain\":100}}," +
+                    "\"time\":\"\"," +
+                    "\"sizeQuota\":{\"used\":1234,\"limit\":10000,\"limits\":{}}," +
+                    "\"user\":\"user\"" +
+                    "}" +
+                "}";
+
+            assertThatThrownBy(() -> QUOTA_EVENT_MODULE.fromJson(quotaUsageUpdatedEvent).get())
+                .isInstanceOf(NoSuchElementException.class);
+        }
+    }
+}


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