diff --git a/mailbox/event/json/pom.xml b/mailbox/event/json/pom.xml new file mode 100644 index 00000000000..bc2621d3bed --- /dev/null +++ b/mailbox/event/json/pom.xml @@ -0,0 +1,155 @@ + + + + 4.0.0 + + + apache-james-mailbox + org.apache.james + 3.3.0-SNAPSHOT + ../../pom.xml + + + apache-james-mailbox-event-json + Apache James :: Mailbox :: Event :: JSON + Apache James Mailbox Event JSON Scala Serialization + + + 2.12 + ${scala.base}.7 + + + + + com.beachape + enumeratum_${scala.base} + 1.5.13 + + + com.typesafe.play + play-json_${scala.base} + 2.6.10 + + + net.javacrumbs.json-unit + json-unit-assertj + test + + + org.apache.james + apache-james-mailbox-api + + + org.assertj + assertj-core + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.junit.jupiter + junit-jupiter-params + test + + + org.julienrf + play-json-derived-codecs_${scala.base} + 4.0.1 + + + org.scala-lang + scala-library + ${scala.version} + + + org.scala-lang.modules + scala-java8-compat_${scala.base} + 0.9.0 + + + + + + + + net.alchim31.maven + scala-maven-plugin + 3.4.4 + + + org.apache.maven.plugins + maven-compiler-plugin + 2.0.2 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + true + 1C + + + + net.alchim31.maven + scala-maven-plugin + + + scala-compile-first + process-resources + + add-source + compile + + + + scala-test-compile + process-test-resources + + testCompile + + + + + -Xlog-implicits + + + + org.apache.maven.plugins + maven-compiler-plugin + + + compile + + compile + + + + + + + + \ No newline at end of file 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 new file mode 100644 index 00000000000..26be6d68558 --- /dev/null +++ b/mailbox/event/json/src/main/scala/org/apache/james/event/json/QuotaEvent.scala @@ -0,0 +1,135 @@ +/** ************************************************************** + * 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) + } +} 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 new file mode 100644 index 00000000000..9dc3a04abd1 --- /dev/null +++ b/mailbox/event/json/src/test/java/org/apache/james/event/json/QuotaEventTest.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 QuotaEventTest { + + private static final User USER = User.fromUsername("user"); + private static final QuotaRoot QUOTA_ROOT = QuotaRoot.quotaRoot("foo", Optional.empty()); + private static final Quota QUOTA_COUNT = Quota.builder() + .used(QuotaCount.count(12)) + .computedLimit(QuotaCount.count(100)) + .build(); + private static final Quota QUOTA_SIZE = Quota.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 countQuota) { + return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, countQuota, QUOTA_SIZE, INSTANT); + } + + @Nested + class LimitedQuotaCount { + + private Quota limitedQuotaCountByScopes(Quota.Scope scope) { + return Quota.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 unLimitedQuotaCountByScopes(Quota.Scope scope) { + return Quota.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) { + return new MailboxListener.QuotaUsageUpdatedEvent(USER, QUOTA_ROOT, QUOTA_COUNT, quotaSize, INSTANT); + } + + @Nested + class LimitedQuotaSize { + + private Quota limitedQuotaSizeByScopes(Quota.Scope scope) { + return Quota.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 unLimitedQuotaSizeByScopes(Quota.Scope scope) { + return Quota.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); + } + } +} diff --git a/mailbox/pom.xml b/mailbox/pom.xml index ff409ce1b82..60cbe444e3f 100644 --- a/mailbox/pom.xml +++ b/mailbox/pom.xml @@ -40,6 +40,7 @@ caching cassandra elasticsearch + event/json jpa lucene maildir