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/05/30 02:24:12 UTC

[01/14] james-project git commit: JAMES-2404 Add a new utility class in order to extract common parameters

Repository: james-project
Updated Branches:
  refs/heads/master 0bde59ba8 -> f56c0bbef


JAMES-2404 Add a new utility class in order to extract common parameters


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

Branch: refs/heads/master
Commit: e5f9d00035b0b279cc98715e30ea3bf8ca1f3ce1
Parents: 2129cba
Author: Antoine Duprat <ad...@linagora.com>
Authored: Fri May 25 11:11:25 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:15:36 2018 +0200

----------------------------------------------------------------------
 .../webadmin/utils/ParametersExtractor.java     |  92 +++++++++
 .../webadmin/utils/ParametersExtractorTest.java | 206 +++++++++++++++++++
 .../james/webadmin/routes/MailQueueRoutes.java  |  18 +-
 .../routes/MailQueueRoutesUnitTest.java         |  34 ---
 .../webadmin/routes/MailRepositoriesRoutes.java |  46 +----
 5 files changed, 303 insertions(+), 93 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/e5f9d000/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ParametersExtractor.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ParametersExtractor.java b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ParametersExtractor.java
new file mode 100644
index 0000000..2cba692
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/main/java/org/apache/james/webadmin/utils/ParametersExtractor.java
@@ -0,0 +1,92 @@
+/****************************************************************
+ * 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.webadmin.utils;
+
+import java.util.Optional;
+
+import org.apache.james.util.streams.Limit;
+import org.apache.james.util.streams.Offset;
+import org.eclipse.jetty.http.HttpStatus;
+
+import com.google.common.base.Strings;
+
+import spark.Request;
+
+public class ParametersExtractor {
+
+    public static final String LIMIT_PARAMETER_NAME = "limit";
+    public static final String OFFSET_PARAMETER_NAME = "offset";
+
+    public static Limit extractLimit(Request request) {
+        return Limit.from(assertPositiveInteger(request, LIMIT_PARAMETER_NAME)
+                .map(value -> assertNotZero(value, LIMIT_PARAMETER_NAME)));
+    }
+
+    public static Offset extractOffset(Request request) {
+        return Offset.from(assertPositiveInteger(request, OFFSET_PARAMETER_NAME));
+    }
+
+    public static Optional<Double> extractPositiveDouble(Request request, String parameterName) {
+        return extractPositiveNumber(request, parameterName)
+                .map(Number::doubleValue);
+    }
+
+    private static Optional<Integer> assertPositiveInteger(Request request, String parameterName) {
+        return extractPositiveNumber(request, parameterName)
+                .map(Number::intValue);
+    }
+
+    private static Optional<Number> extractPositiveNumber(Request request, String parameterName) {
+        try {
+            return Optional.ofNullable(request.queryParams(parameterName))
+                .filter(s -> !Strings.isNullOrEmpty(s))
+                .map(Double::valueOf)
+                .map(value -> assertPositive(value, parameterName));
+        } catch (NumberFormatException e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .cause(e)
+                .message("Can not parse " + parameterName)
+                .haltError();
+        }
+    }
+
+    private static Number assertPositive(Number value, String parameterName) {
+        if (value.doubleValue() < 0) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message(parameterName + " can not be negative")
+                .haltError();
+        }
+        return value;
+    }
+
+    private static int assertNotZero(int value, String parameterName) {
+        if (value == 0) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message(parameterName + " can not be equal to zero")
+                .haltError();
+        }
+        return value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/e5f9d000/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/ParametersExtractorTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/ParametersExtractorTest.java b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/ParametersExtractorTest.java
new file mode 100644
index 0000000..000fcbf
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-core/src/test/java/org/apache/james/webadmin/utils/ParametersExtractorTest.java
@@ -0,0 +1,206 @@
+/****************************************************************
+ * 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.webadmin.utils;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Optional;
+
+import org.apache.james.util.streams.Limit;
+import org.apache.james.util.streams.Offset;
+import org.junit.Test;
+
+import spark.HaltException;
+import spark.Request;
+
+public class ParametersExtractorTest {
+
+    @Test
+    public void extractLimitShouldReturnUnlimitedWhenNotInParameters() {
+        Request request = mock(Request.class);
+        when(request.queryParams("limit"))
+            .thenReturn(null);
+
+        Limit limit = ParametersExtractor.extractLimit(request);
+
+        assertThat(limit).isEqualTo(Limit.unlimited());
+    }
+
+    @Test
+    public void extractLimitShouldReturnUnlimitedWhenPresentInParametersButEmpty() {
+        Request request = mock(Request.class);
+        when(request.queryParams("limit"))
+            .thenReturn("");
+
+        Limit limit = ParametersExtractor.extractLimit(request);
+
+        assertThat(limit).isEqualTo(Limit.unlimited());
+    }
+
+    @Test
+    public void extractLimitShouldReturnTheLimitWhenPresentInParameters() {
+        Request request = mock(Request.class);
+        when(request.queryParams("limit"))
+            .thenReturn("123");
+
+        Limit limit = ParametersExtractor.extractLimit(request);
+
+        assertThat(limit).isEqualTo(Limit.from(123));
+    }
+
+    @Test
+    public void extractLimitShouldThrowWhenNegativeLimit() {
+        Request request = mock(Request.class);
+        when(request.queryParams("limit"))
+            .thenReturn("-123");
+
+        assertThatThrownBy(() -> ParametersExtractor.extractLimit(request))
+            .isInstanceOf(HaltException.class);
+    }
+
+    @Test
+    public void extractLimitShouldThrowWhenZeroLimit() {
+        Request request = mock(Request.class);
+        when(request.queryParams("limit"))
+            .thenReturn("0");
+
+        assertThatThrownBy(() -> ParametersExtractor.extractLimit(request))
+            .isInstanceOf(HaltException.class);
+    }
+
+    @Test
+    public void extractOffsetShouldReturnNoneWhenNotInParameters() {
+        Request request = mock(Request.class);
+        when(request.queryParams("offset"))
+            .thenReturn(null);
+
+        Offset offset = ParametersExtractor.extractOffset(request);
+
+        assertThat(offset).isEqualTo(Offset.none());
+    }
+
+    @Test
+    public void extractOffsetShouldReturnNoneWhenPresentInParametersButEmpty() {
+        Request request = mock(Request.class);
+        when(request.queryParams("offset"))
+            .thenReturn("");
+
+        Offset offset= ParametersExtractor.extractOffset(request);
+
+        assertThat(offset).isEqualTo(Offset.none());
+    }
+
+    @Test
+    public void extractOffsetShouldReturnTheOffsetWhenPresentInParameters() {
+        Request request = mock(Request.class);
+        when(request.queryParams("offset"))
+            .thenReturn("123");
+
+        Offset offset = ParametersExtractor.extractOffset(request);
+
+        assertThat(offset).isEqualTo(Offset.from(123));
+    }
+
+    @Test
+    public void extractOffsetShouldThrowWhenNegativeOffset() {
+        Request request = mock(Request.class);
+        when(request.queryParams("offset"))
+            .thenReturn("-123");
+
+        assertThatThrownBy(() -> ParametersExtractor.extractOffset(request))
+            .isInstanceOf(HaltException.class);
+    }
+
+    @Test
+    public void extractOffsetShouldReturnNoneWhenZeroLimit() {
+        Request request = mock(Request.class);
+        when(request.queryParams("offset"))
+            .thenReturn("0");
+
+        Offset offset = ParametersExtractor.extractOffset(request);
+
+        assertThat(offset).isEqualTo(Offset.none());
+    }
+    
+    
+
+    @Test
+    public void extractPositiveDoubleShouldReturnEmptyWhenNotInParameters() {
+        String parameterName = "param";
+        Request request = mock(Request.class);
+        when(request.queryParams(parameterName))
+            .thenReturn(null);
+
+        Optional<Double> result = ParametersExtractor.extractPositiveDouble(request, parameterName);
+
+        assertThat(result).isEmpty();
+    }
+
+    @Test
+    public void extractPositiveDoubleShouldReturnNoneWhenPresentInParametersButEmpty() {
+        String parameterName = "param";
+        Request request = mock(Request.class);
+        when(request.queryParams(parameterName))
+            .thenReturn("");
+
+        Optional<Double> result = ParametersExtractor.extractPositiveDouble(request, parameterName);
+
+        assertThat(result).isEmpty();
+    }
+
+    @Test
+    public void extractPositiveDoubleShouldReturnTheDoubleWhenPresentInParameters() {
+        String parameterName = "param";
+        Request request = mock(Request.class);
+        when(request.queryParams(parameterName))
+            .thenReturn("123");
+
+        Optional<Double> result = ParametersExtractor.extractPositiveDouble(request, parameterName);
+
+        assertThat(result).contains(Double.valueOf(123));
+    }
+
+    @Test
+    public void extractPositiveDoubleShouldThrowWhenNegativePositiveDouble() {
+        String parameterName = "param";
+        Request request = mock(Request.class);
+        when(request.queryParams(parameterName))
+            .thenReturn("-123");
+
+        assertThatThrownBy(() -> {
+            ParametersExtractor.extractPositiveDouble(request, parameterName);
+        })
+            .isInstanceOf(HaltException.class);
+    }
+
+    @Test
+    public void extractPositiveDoubleShouldReturnZeroWhenZeroLimit() {
+        String parameterName = "param";
+        Request request = mock(Request.class);
+        when(request.queryParams(parameterName))
+            .thenReturn("0");
+
+        Optional<Double> result = ParametersExtractor.extractPositiveDouble(request, parameterName);
+
+        assertThat(result).contains(Double.valueOf(0));
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/e5f9d000/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
index ee43f56..2f5b6fd 100644
--- a/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/routes/MailQueueRoutes.java
@@ -52,6 +52,7 @@ import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
 import org.apache.james.webadmin.utils.JsonExtractException;
 import org.apache.james.webadmin.utils.JsonExtractor;
 import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.james.webadmin.utils.ParametersExtractor;
 import org.eclipse.jetty.http.HttpStatus;
 
 import com.github.fge.lambdas.Throwing;
@@ -217,7 +218,7 @@ public class MailQueueRoutes implements Routes {
     private List<MailQueueItemDTO> listMails(Request request) {
         String mailQueueName = request.params(MAIL_QUEUE_NAME);
         return mailQueueFactory.getQueue(mailQueueName)
-                .map(name -> listMails(name, isDelayed(request.queryParams(DELAYED_QUERY_PARAM)), limit(request.queryParams(LIMIT_QUERY_PARAM))))
+                .map(name -> listMails(name, isDelayed(request.queryParams(DELAYED_QUERY_PARAM)), ParametersExtractor.extractLimit(request)))
                 .orElseThrow(
                     () -> ErrorResponder.builder()
                         .message(String.format("%s can not be found", mailQueueName))
@@ -231,21 +232,6 @@ public class MailQueueRoutes implements Routes {
                 .map(Boolean::parseBoolean);
     }
 
-    @VisibleForTesting Limit limit(String limitAsString) throws HaltException {
-        try {
-            return Optional.ofNullable(limitAsString)
-                    .map(Integer::parseInt)
-                    .map(Limit::limit)
-                    .orElseGet(() -> Limit.from(DEFAULT_LIMIT_VALUE));
-        } catch (IllegalArgumentException e) {
-            throw ErrorResponder.builder()
-                .message(String.format("limit can't be less or equals to zero"))
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.NOT_FOUND)
-                .haltError();
-        }
-    }
-
     private List<MailQueueItemDTO> listMails(ManageableMailQueue queue, Optional<Boolean> isDelayed, Limit limit) {
         try {
             return limit.applyOnStream(Iterators.toStream(queue.browse()))

http://git-wip-us.apache.org/repos/asf/james-project/blob/e5f9d000/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesUnitTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesUnitTest.java b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesUnitTest.java
index 3f53ed0..5e1ef9e 100644
--- a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesUnitTest.java
+++ b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesUnitTest.java
@@ -20,20 +20,16 @@
 package org.apache.james.webadmin.routes;
 
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 
 import java.util.Optional;
 
 import org.apache.james.queue.api.MailQueueFactory;
 import org.apache.james.queue.api.ManageableMailQueue;
 import org.apache.james.task.MemoryTaskManager;
-import org.apache.james.util.streams.Limit;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.junit.Before;
 import org.junit.Test;
 
-import spark.HaltException;
-
 public class MailQueueRoutesUnitTest {
 
     MailQueueRoutes testee;
@@ -68,34 +64,4 @@ public class MailQueueRoutesUnitTest {
         Optional<Boolean> delayed = testee.isDelayed("abc");
         assertThat(delayed).contains(false);
     }
-
-    @Test
-    public void limitShouldBeEqualsToDefaultValueWhenNull() {
-        Limit limit = testee.limit(null);
-        assertThat(limit.getLimit()).contains(MailQueueRoutes.DEFAULT_LIMIT_VALUE);
-    }
-
-    @Test
-    public void limitShouldBeEqualsToTheValueWhenOne() {
-        Limit limit = testee.limit("123");
-        assertThat(limit.getLimit()).contains(123);
-    }
-
-    @Test
-    public void limitShouldThrowWhenOtherValue() {
-        assertThatThrownBy(() -> testee.limit("abc"))
-            .isInstanceOf(HaltException.class);
-    }
-
-    @Test
-    public void limitShouldThrowWhenEqualsToZero() {
-        assertThatThrownBy(() -> testee.limit("0"))
-            .isInstanceOf(HaltException.class);
-    }
-
-    @Test
-    public void limitShouldThrowWhenLessThanZero() {
-        assertThatThrownBy(() -> testee.limit("-1"))
-            .isInstanceOf(HaltException.class);
-    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/e5f9d000/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
index a90323b..dfe1fcf 100644
--- a/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailrepository/src/main/java/org/apache/james/webadmin/routes/MailRepositoriesRoutes.java
@@ -50,10 +50,9 @@ import org.apache.james.webadmin.service.ReprocessingService;
 import org.apache.james.webadmin.utils.ErrorResponder;
 import org.apache.james.webadmin.utils.ErrorResponder.ErrorType;
 import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.james.webadmin.utils.ParametersExtractor;
 import org.eclipse.jetty.http.HttpStatus;
 
-import com.google.common.base.Strings;
-
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiImplicitParams;
@@ -135,9 +134,8 @@ public class MailRepositoriesRoutes implements Routes {
     })
     public void defineListMails() {
         service.get(MAIL_REPOSITORIES + "/:encodedUrl/mails", (request, response) -> {
-            Offset offset = Offset.from(assertPositiveInteger(request, "offset"));
-            Limit limit = Limit.from(assertPositiveInteger(request, "limit")
-                .map(value -> assertNotZero(value, "limit")));
+            Offset offset = ParametersExtractor.extractOffset(request);
+            Limit limit = ParametersExtractor.extractLimit(request);
             String encodedUrl = request.params("encodedUrl");
             String url = URLDecoder.decode(encodedUrl, StandardCharsets.UTF_8.displayName());
             try {
@@ -401,42 +399,4 @@ public class MailRepositoriesRoutes implements Routes {
     private String decodedRepositoryUrl(Request request) throws UnsupportedEncodingException {
         return URLDecoder.decode(request.params("encodedUrl"), StandardCharsets.UTF_8.displayName());
     }
-
-    private Optional<Integer> assertPositiveInteger(Request request, String parameterName) {
-        try {
-            return Optional.ofNullable(request.queryParams(parameterName))
-                .filter(s -> !Strings.isNullOrEmpty(s))
-                .map(Integer::valueOf)
-                .map(value -> assertPositive(value, parameterName));
-        } catch (NumberFormatException e) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .cause(e)
-                .message("Can not parse " + parameterName)
-                .haltError();
-        }
-    }
-
-    private int assertPositive(int value, String parameterName) {
-        if (value < 0) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message(parameterName + " can not be negative")
-                .haltError();
-        }
-        return value;
-    }
-
-    private int assertNotZero(int value, String parameterName) {
-        if (value == 0) {
-            throw ErrorResponder.builder()
-                .statusCode(HttpStatus.BAD_REQUEST_400)
-                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
-                .message(parameterName + " can not be equal to zero")
-                .haltError();
-        }
-        return value;
-    }
 }


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


[07/14] james-project git commit: JAMES-2404 Guice injections for QuotaSearcher

Posted by bt...@apache.org.
JAMES-2404 Guice injections for QuotaSearcher


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

Branch: refs/heads/master
Commit: 6a327468174959da22bacf1a7379aeab8948aec0
Parents: 350bc6c
Author: benwa <bt...@linagora.com>
Authored: Mon May 28 12:05:00 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 pom.xml                                         |  5 ++
 server/container/guice/cassandra-guice/pom.xml  |  4 ++
 .../mailbox/ElasticSearchMailboxModule.java     |  5 ++
 .../ElasticSearchQuotaSearcherModule.java       | 67 ++++++++++++++++++++
 server/container/guice/jpa-guice/pom.xml        |  4 ++
 .../james/modules/mailbox/JPAMailboxModule.java |  1 +
 .../modules/mailbox/JPAQuotaSearchModule.java   | 34 ++++++++++
 server/container/guice/memory-guice/pom.xml     |  4 ++
 .../modules/mailbox/MemoryMailboxModule.java    |  1 +
 .../mailbox/MemoryQuotaSearchModule.java        | 34 ++++++++++
 10 files changed, 159 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 805fb3d..6709cf9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -825,6 +825,11 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
+                <artifactId>apache-james-mailbox-quota-search-elasticsearch</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
                 <artifactId>apache-james-mailbox-scanning-search</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/cassandra-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/pom.xml b/server/container/guice/cassandra-guice/pom.xml
index 54f4958..9ec854d 100644
--- a/server/container/guice/cassandra-guice/pom.xml
+++ b/server/container/guice/cassandra-guice/pom.xml
@@ -78,6 +78,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search-elasticsearch</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>apache-james-mailbox-tika</artifactId>
             <type>test-jar</type>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
index 27baee3..48e254b 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
@@ -43,6 +43,7 @@ import org.apache.james.mailbox.model.MailboxId;
 import org.apache.james.mailbox.model.MessageId;
 import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
 import org.apache.james.mailbox.store.search.MessageSearchIndex;
+import org.apache.james.quota.search.elasticsearch.QuotaSearchIndexCreationUtil;
 import org.apache.james.utils.PropertiesProvider;
 import org.apache.james.utils.RetryExecutorUtil;
 import org.elasticsearch.client.Client;
@@ -62,6 +63,8 @@ public class ElasticSearchMailboxModule extends AbstractModule {
 
     @Override
     protected void configure() {
+        install(new ElasticSearchQuotaSearcherModule());
+
         bind(ElasticSearchListeningMessageSearchIndex.class).in(Scopes.SINGLETON);
         bind(MessageSearchIndex.class).to(ElasticSearchListeningMessageSearchIndex.class);
         bind(ListeningMessageSearchIndex.class).to(ElasticSearchListeningMessageSearchIndex.class);
@@ -129,6 +132,8 @@ public class ElasticSearchMailboxModule extends AbstractModule {
             configuration.getWriteAliasMailboxName(),
             configuration.getIndexMailboxName());
 
+        QuotaSearchIndexCreationUtil.prepareDefaultClient(client);
+
         return client;
     }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
new file mode 100644
index 0000000..0a10aac
--- /dev/null
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
@@ -0,0 +1,67 @@
+/****************************************************************
+ * 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.modules.mailbox;
+
+import java.util.concurrent.ExecutorService;
+
+import javax.inject.Named;
+
+import org.apache.james.backends.es.ElasticSearchIndexer;
+import org.apache.james.mailbox.MailboxListener;
+import org.apache.james.quota.search.QuotaSearcher;
+import org.apache.james.quota.search.elasticsearch.ElasticSearchQuotaSearcher;
+import org.apache.james.quota.search.elasticsearch.QuotaRatioElasticSearchConstants;
+import org.apache.james.quota.search.elasticsearch.events.ElasticSearchQuotaMailboxListener;
+import org.apache.james.quota.search.elasticsearch.json.QuotaRatioToElasticSearchJson;
+import org.elasticsearch.client.Client;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Provides;
+import com.google.inject.Singleton;
+import com.google.inject.multibindings.Multibinder;
+
+public class ElasticSearchQuotaSearcherModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        Multibinder.newSetBinder(binder(), MailboxListener.class)
+            .addBinding()
+            .to(ElasticSearchQuotaMailboxListener.class);
+    }
+
+    @Provides
+    @Singleton
+    public QuotaSearcher provideSearcher(Client client, ElasticSearchConfiguration configuration) {
+        return new ElasticSearchQuotaSearcher(client,
+            QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS);
+    }
+
+    @Provides
+    @Singleton
+    public ElasticSearchQuotaMailboxListener provideListener(Client client,
+                                                             @Named("AsyncExecutor") ExecutorService executor,
+                                                             ElasticSearchConfiguration configuration) {
+        return new ElasticSearchQuotaMailboxListener(
+            new ElasticSearchIndexer(client,
+                executor,
+                QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS,
+                QuotaRatioElasticSearchConstants.QUOTA_RATIO_TYPE),
+                new QuotaRatioToElasticSearchJson());
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/jpa-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/pom.xml b/server/container/guice/jpa-guice/pom.xml
index 6e1f5f5..c5ed697 100644
--- a/server/container/guice/jpa-guice/pom.xml
+++ b/server/container/guice/jpa-guice/pom.xml
@@ -51,6 +51,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search-scanning</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>apache-james-mailbox-lucene</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAMailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAMailboxModule.java b/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAMailboxModule.java
index eb3c310..fb8caba 100644
--- a/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAMailboxModule.java
+++ b/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAMailboxModule.java
@@ -78,6 +78,7 @@ public class JPAMailboxModule extends AbstractModule {
     @Override
     protected void configure() {
         install(new JpaQuotaModule());
+        install(new JPAQuotaSearchModule());
 
         bind(JPAMailboxSessionMapperFactory.class).in(Scopes.SINGLETON);
         bind(OpenJPAMailboxManager.class).in(Scopes.SINGLETON);

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAQuotaSearchModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAQuotaSearchModule.java b/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAQuotaSearchModule.java
new file mode 100644
index 0000000..dbb0e3f
--- /dev/null
+++ b/server/container/guice/jpa-guice/src/main/java/org/apache/james/modules/mailbox/JPAQuotaSearchModule.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.modules.mailbox;
+
+import org.apache.james.quota.search.QuotaSearcher;
+import org.apache.james.quota.search.scanning.ScanningQuotaSearcher;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+
+public class JPAQuotaSearchModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        bind(ScanningQuotaSearcher.class).in(Scopes.SINGLETON);
+        bind(QuotaSearcher.class).to(ScanningQuotaSearcher.class);
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/memory-guice/pom.xml
----------------------------------------------------------------------
diff --git a/server/container/guice/memory-guice/pom.xml b/server/container/guice/memory-guice/pom.xml
index bb2d483..f671506 100644
--- a/server/container/guice/memory-guice/pom.xml
+++ b/server/container/guice/memory-guice/pom.xml
@@ -50,6 +50,10 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search-scanning</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>apache-mailet-base</artifactId>
             <type>test-jar</type>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
index 34041f5..85c4c5f 100644
--- a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryMailboxModule.java
@@ -79,6 +79,7 @@ public class MemoryMailboxModule extends AbstractModule {
     protected void configure() {
         install(new DefaultEventModule());
         install(new MemoryQuotaModule());
+        install(new MemoryQuotaSearchModule());
 
         bind(MessageMapperFactory.class).to(InMemoryMailboxSessionMapperFactory.class);
         bind(MailboxMapperFactory.class).to(InMemoryMailboxSessionMapperFactory.class);

http://git-wip-us.apache.org/repos/asf/james-project/blob/6a327468/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryQuotaSearchModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryQuotaSearchModule.java b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryQuotaSearchModule.java
new file mode 100644
index 0000000..e3b1bd2
--- /dev/null
+++ b/server/container/guice/memory-guice/src/main/java/org/apache/james/modules/mailbox/MemoryQuotaSearchModule.java
@@ -0,0 +1,34 @@
+/****************************************************************
+ * 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.modules.mailbox;
+
+import org.apache.james.quota.search.QuotaSearcher;
+import org.apache.james.quota.search.scanning.ScanningQuotaSearcher;
+
+import com.google.inject.AbstractModule;
+import com.google.inject.Scopes;
+
+public class MemoryQuotaSearchModule extends AbstractModule {
+    @Override
+    protected void configure() {
+        bind(ScanningQuotaSearcher.class).in(Scopes.SINGLETON);
+        bind(QuotaSearcher.class).to(ScanningQuotaSearcher.class);
+    }
+}


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


[05/14] james-project git commit: JAMES-2404 Implement REST endpoints for QuotaSearch

Posted by bt...@apache.org.
JAMES-2404 Implement REST endpoints for QuotaSearch

Provide scanning based tests


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

Branch: refs/heads/master
Commit: 7da78ab064c2613224fa2958a0fb6346c293b017
Parents: 5c4af30
Author: benwa <bt...@linagora.com>
Authored: Mon May 28 11:37:00 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:52 2018 +0200

----------------------------------------------------------------------
 .../apache/james/quota/search/QuotaQuery.java   |  15 +++
 .../webadmin/dto/UsersQuotaDetailsDTO.java      |   6 +-
 .../james/webadmin/routes/UserQuotaRoutes.java  |  98 ++++++++++++++++-
 .../webadmin/service/UserQuotaService.java      |  19 +++-
 .../webadmin/routes/UserQuotaRoutesTest.java    | 105 +++++++++++++++++++
 5 files changed, 236 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/7da78ab0/mailbox/plugin/quota-search/src/main/java/org/apache/james/quota/search/QuotaQuery.java
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search/src/main/java/org/apache/james/quota/search/QuotaQuery.java b/mailbox/plugin/quota-search/src/main/java/org/apache/james/quota/search/QuotaQuery.java
index b18ee47..ecd0d66 100644
--- a/mailbox/plugin/quota-search/src/main/java/org/apache/james/quota/search/QuotaQuery.java
+++ b/mailbox/plugin/quota-search/src/main/java/org/apache/james/quota/search/QuotaQuery.java
@@ -45,16 +45,31 @@ public class QuotaQuery {
             return this;
         }
 
+        public Builder moreThan(Optional<QuotaBoundary> quotaBoundary) {
+            quotaBoundary.ifPresent(this::moreThan);
+            return this;
+        }
+
         public Builder lessThan(QuotaBoundary quotaBoundary) {
             clauses.add(QuotaClause.lessThan(quotaBoundary));
             return this;
         }
 
+        public Builder lessThan(Optional<QuotaBoundary> quotaBoundary) {
+            quotaBoundary.ifPresent(this::lessThan);
+            return this;
+        }
+
         public Builder hasDomain(Domain domain) {
             clauses.add(QuotaClause.hasDomain(domain));
             return this;
         }
 
+        public Builder hasDomain(Optional<Domain> domain) {
+            domain.ifPresent(this::hasDomain);
+            return this;
+        }
+
         public Builder withLimit(Limit limit) {
             this.limit = Optional.of(limit);
             return this;

http://git-wip-us.apache.org/repos/asf/james-project/blob/7da78ab0/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
index 146fc51..dfaf318 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
@@ -20,8 +20,6 @@
 
 package org.apache.james.webadmin.dto;
 
-import javax.mail.internet.AddressException;
-
 import org.apache.james.core.User;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
@@ -69,8 +67,8 @@ public class UsersQuotaDetailsDTO {
     }
 
     @JsonProperty(USERNAME)
-    public String getUser() throws AddressException {
-        return user.asMailAddress().asPrettyString();
+    public String getUser() {
+        return user.asString();
     }
 
     public QuotaDetailsDTO getDetail() {

http://git-wip-us.apache.org/repos/asf/james-project/blob/7da78ab0/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
index 81d6803..a991045 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
@@ -33,9 +33,14 @@ import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 
+import org.apache.james.core.Domain;
 import org.apache.james.core.User;
 import org.apache.james.mailbox.quota.QuotaCount;
 import org.apache.james.mailbox.quota.QuotaSize;
+import org.apache.james.quota.search.Limit;
+import org.apache.james.quota.search.Offset;
+import org.apache.james.quota.search.QuotaBoundary;
+import org.apache.james.quota.search.QuotaQuery;
 import org.apache.james.user.api.UsersRepository;
 import org.apache.james.user.api.UsersRepositoryException;
 import org.apache.james.webadmin.Routes;
@@ -48,6 +53,7 @@ import org.apache.james.webadmin.utils.JsonExtractException;
 import org.apache.james.webadmin.utils.JsonExtractor;
 import org.apache.james.webadmin.utils.JsonTransformer;
 import org.apache.james.webadmin.utils.JsonTransformerModule;
+import org.apache.james.webadmin.utils.ParametersExtractor;
 import org.apache.james.webadmin.validation.Quotas;
 import org.eclipse.jetty.http.HttpStatus;
 
@@ -61,12 +67,16 @@ import spark.Request;
 import spark.Service;
 
 @Api(tags = "UserQuota")
-@Path(UserQuotaRoutes.QUOTA_ENDPOINT)
+@Path(UserQuotaRoutes.MAIN_QUOTA_ENDPOINT)
 @Produces("application/json")
 public class UserQuotaRoutes implements Routes {
 
     private static final String USER = "user";
-    static final String QUOTA_ENDPOINT = "/quota/users/:" + USER;
+    private static final String MIN_OCCUPATION_RATIO = "minOccupationRatio";
+    private static final String MAX_OCCUPATION_RATIO = "maxOccupationRatio";
+    private static final String DOMAIN = "domain";
+    static final String MAIN_QUOTA_ENDPOINT = "/quota/users";
+    private static final String QUOTA_ENDPOINT = MAIN_QUOTA_ENDPOINT + "/:" + USER;
     private static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
     private static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
 
@@ -98,6 +108,8 @@ public class UserQuotaRoutes implements Routes {
 
         defineGetQuota();
         defineUpdateQuota();
+
+        defineGetUsersQuota();
     }
 
     @PUT
@@ -139,6 +151,88 @@ public class UserQuotaRoutes implements Routes {
         }, jsonTransformer);
     }
 
+    @GET
+    @ApiOperation(
+        value = "Reading count and size at the same time",
+        notes = "If there is no limitation for count and/or size, the returned value will be -1"
+    )
+    @ApiImplicitParams({
+        @ApiImplicitParam(
+                required = false,
+                name = "minOccuptationRatio",
+                paramType = "query parameter",
+                dataType = "Double",
+                example = "?minOccuptationRatio=0.8",
+                value = "If present, filter the users with occupation ratio lesser than this value."),
+        @ApiImplicitParam(
+                required = false,
+                name = "maxOccupationRatio",
+                paramType = "query parameter",
+                dataType = "Double",
+                example = "?maxOccupationRatio=0.99",
+                value = "If present, filter the users with occupation ratio greater than this value."),
+        @ApiImplicitParam(
+                required = false,
+                paramType = "query parameter",
+                name = "limit",
+                dataType = "Integer",
+                example = "?limit=100",
+                value = "If present, fixes the maximal number of key returned in that call. Must be more than zero if specified."),
+        @ApiImplicitParam(
+                required = false,
+                name = "offset",
+                paramType = "query parameter",
+                dataType = "Integer",
+                example = "?offset=100",
+                value = "If present, skips the given number of key in the output."),
+        @ApiImplicitParam(
+                required = false,
+                name = "domain",
+                paramType = "query parameter",
+                dataType = "String",
+                example = "?domain=james.org",
+                value = "If present, filter the users by this domain.")
+    })
+    @ApiResponses(value = {
+            @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = QuotaDetailsDTO.class),
+            @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "Validation issues with parameters"),
+            @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+    })
+    public void defineGetUsersQuota() {
+        service.get(MAIN_QUOTA_ENDPOINT, (request, response) -> {
+            QuotaQuery quotaQuery = QuotaQuery.builder()
+                .lessThan(extractQuotaBoundary(request, MAX_OCCUPATION_RATIO))
+                .moreThan(extractQuotaBoundary(request, MIN_OCCUPATION_RATIO))
+                .hasDomain(extractDomain(request, DOMAIN))
+                .withLimit(extractLimit(request))
+                .withOffset(extractOffset(request))
+                .build();
+
+            return userQuotaService.getUsersQuota(quotaQuery);
+        }, jsonTransformer);
+    }
+
+    public Optional<Domain> extractDomain(Request request, String parameterName) {
+        return Optional.ofNullable(request.queryParams(parameterName)).map(Domain::of);
+    }
+
+    public Optional<QuotaBoundary> extractQuotaBoundary(Request request, String parameterName) {
+        return ParametersExtractor.extractPositiveDouble(request, parameterName)
+            .map(QuotaBoundary::new);
+    }
+
+    public Limit extractLimit(Request request) {
+        return ParametersExtractor.extractLimit(request)
+            .getLimit()
+            .map(Limit::of)
+            .orElse(Limit.unlimited());
+    }
+
+    public Offset extractOffset(Request request) {
+        return Offset.of(ParametersExtractor.extractOffset(request)
+            .getOffset());
+    }
+
     @DELETE
     @Path("/size")
     @ApiOperation(value = "Removing per user mail size limitation by updating to unlimited value")

http://git-wip-us.apache.org/repos/asf/james-project/blob/7da78ab0/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
index 31a934f..6fdb9c0 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
@@ -18,6 +18,7 @@
  ****************************************************************/
 package org.apache.james.webadmin.service;
 
+import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.function.Function;
@@ -34,10 +35,14 @@ import org.apache.james.mailbox.quota.QuotaCount;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaSize;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
+import org.apache.james.quota.search.QuotaQuery;
+import org.apache.james.quota.search.QuotaSearcher;
 import org.apache.james.webadmin.dto.QuotaDTO;
 import org.apache.james.webadmin.dto.QuotaDetailsDTO;
+import org.apache.james.webadmin.dto.UsersQuotaDetailsDTO;
 
 import com.github.fge.lambdas.Throwing;
+import com.github.steveash.guavate.Guavate;
 import com.google.common.collect.Sets;
 
 public class UserQuotaService {
@@ -45,12 +50,14 @@ public class UserQuotaService {
     private final MaxQuotaManager maxQuotaManager;
     private final QuotaManager quotaManager;
     private final UserQuotaRootResolver userQuotaRootResolver;
+    private final QuotaSearcher quotaSearcher;
 
     @Inject
-    public UserQuotaService(MaxQuotaManager maxQuotaManager, QuotaManager quotaManager, UserQuotaRootResolver userQuotaRootResolver) {
+    public UserQuotaService(MaxQuotaManager maxQuotaManager, QuotaManager quotaManager, UserQuotaRootResolver userQuotaRootResolver, QuotaSearcher quotaSearcher) {
         this.maxQuotaManager = maxQuotaManager;
         this.quotaManager = quotaManager;
         this.userQuotaRootResolver = userQuotaRootResolver;
+        this.quotaSearcher = quotaSearcher;
     }
 
     public void defineQuota(User user, QuotaDTO quota) {
@@ -119,4 +126,14 @@ public class UserQuotaService {
     public void deleteMaxCountQuota(User user) throws MailboxException {
         maxQuotaManager.removeMaxMessage(userQuotaRootResolver.forUser(user));
     }
+
+    public List<UsersQuotaDetailsDTO> getUsersQuota(QuotaQuery quotaQuery) {
+        return quotaSearcher.search(quotaQuery)
+            .stream()
+            .map(Throwing.function(user -> UsersQuotaDetailsDTO.builder()
+                .user(user)
+                .detail(getQuota(user))
+                .build()))
+            .collect(Guavate.toImmutableList());
+    }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/7da78ab0/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index 4373342..8c7bbcd 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -22,6 +22,7 @@ package org.apache.james.webadmin.routes;
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.containsInAnyOrder;
 
 import java.util.Map;
 
@@ -83,6 +84,110 @@ class UserQuotaRoutesTest {
         userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
         currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
     }
+    interface GetUsersQuotaRouteContract {
+        @Test
+        default void getUsersQuotaShouldReturnAllUsersWhenNoParameters() {
+            given()
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    BOB.asString(),
+                    JACK.asString(),
+                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+        }
+
+        @Test
+        default void getUsersQuotaShouldFilterOnDomain() {
+            given()
+                .param("domain", PERDU_COM)
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    BOB.asString(),
+                    JACK.asString()));
+        }
+
+        @Test
+        default void getUsersQuotaShouldLimitValues() {
+            given()
+                .param("limit", 2)
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    BOB.asString(),
+                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+        }
+
+        @Test
+        default void getUsersQuotaShouldAcceptOffset() {
+            given()
+                .param("offset", 1)
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    JACK.asString(),
+                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+        }
+
+        @Test
+        default void getUsersQuotaShouldFilterOnMinOccupationRatio(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
+            UserQuotaRootResolver quotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
+            currentQuotaManager.increase(quotaRootResolver.forUser(BOB), 1, 49);
+            currentQuotaManager.increase(quotaRootResolver.forUser(JACK), 1, 50);
+            currentQuotaManager.increase(quotaRootResolver.forUser(THE_GUY_WITH_STRANGE_DOMAIN), 1, 51);
+
+            given()
+                .param("minOccupationRatio", 0.5)
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    JACK.asString(),
+                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+        }
+
+        @Test
+        default void getUsersQuotaShouldFilterOnMaxOccupationRatio(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
+            UserQuotaRootResolver quotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
+            currentQuotaManager.increase(quotaRootResolver.forUser(BOB), 1, 49);
+            currentQuotaManager.increase(quotaRootResolver.forUser(JACK), 1, 50);
+            currentQuotaManager.increase(quotaRootResolver.forUser(THE_GUY_WITH_STRANGE_DOMAIN), 1, 51);
+
+            given()
+                .param("maxOccupationRatio", 0.5)
+                .get("/quota/users")
+                .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", containsInAnyOrder(
+                    JACK.asString(),
+                    BOB.asString()));
+        }
+
+    }
+
+    @Nested
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class ScanningGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract {
+
+    }
 
     @Nested
     class GetCount {


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


[08/14] james-project git commit: JAMES-2404 Configuration of Quota Search aliases

Posted by bt...@apache.org.
JAMES-2404 Configuration of Quota Search aliases


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

Branch: refs/heads/master
Commit: b5816095bbab124658d9aab5cb30a11799a278ae
Parents: 6a32746
Author: benwa <bt...@linagora.com>
Authored: Mon May 28 14:27:50 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 .../mailbox/ElasticSearchConfiguration.java     | 62 ++++++++++++++-
 .../mailbox/ElasticSearchMailboxModule.java     |  5 +-
 .../ElasticSearchQuotaSearcherModule.java       |  4 +-
 .../mailbox/ElasticSearchConfigurationTest.java | 83 +++++++++++++++++++-
 4 files changed, 143 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b5816095/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
index c19bd96..230e480 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchConfiguration.java
@@ -31,6 +31,7 @@ import org.apache.james.backends.es.ReadAliasName;
 import org.apache.james.backends.es.WriteAliasName;
 import org.apache.james.mailbox.elasticsearch.IndexAttachments;
 import org.apache.james.mailbox.elasticsearch.MailboxElasticSearchConstants;
+import org.apache.james.quota.search.elasticsearch.QuotaRatioElasticSearchConstants;
 import org.apache.james.util.Host;
 import org.apache.james.util.OptionalUtils;
 
@@ -50,6 +51,9 @@ public class ElasticSearchConfiguration {
     public static final String ELASTICSEARCH_ALIAS_WRITE_NAME = "elasticsearch.alias.write.name";
     public static final String ELASTICSEARCH_ALIAS_READ_MAILBOX_NAME = "elasticsearch.alias.read.mailbox.name";
     public static final String ELASTICSEARCH_ALIAS_WRITE_MAILBOX_NAME = "elasticsearch.alias.write.mailbox.name";
+    public static final String ELASTICSEARCH_INDEX_QUOTA_RATIO_NAME = "elasticsearch.index.quota.ratio.name";
+    public static final String ELASTICSEARCH_ALIAS_READ_QUOTA_RATIO_NAME = "elasticsearch.alias.read.quota.ratio.name";
+    public static final String ELASTICSEARCH_ALIAS_WRITE_QUOTA_RATIO_NAME = "elasticsearch.alias.write.quota.ratio.name";
     public static final String ELASTICSEARCH_RETRY_CONNECTION_MIN_DELAY = "elasticsearch.retryConnection.minDelay";
     public static final String ELASTICSEARCH_RETRY_CONNECTION_MAX_RETRIES = "elasticsearch.retryConnection.maxRetries";
     public static final String ELASTICSEARCH_INDEX_ATTACHMENTS = "elasticsearch.indexAttachments";
@@ -68,6 +72,9 @@ public class ElasticSearchConfiguration {
         MailboxElasticSearchConstants.DEFAULT_MAILBOX_INDEX,
         MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS,
         MailboxElasticSearchConstants.DEFAULT_MAILBOX_WRITE_ALIAS,
+        QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_INDEX,
+        QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS,
+        QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS,
         DEFAULT_NB_SHARDS,
         DEFAULT_NB_REPLICA,
         DEFAULT_CONNECTION_MIN_DELAY,
@@ -81,15 +88,23 @@ public class ElasticSearchConfiguration {
         int minDelay = configuration.getInt(ELASTICSEARCH_RETRY_CONNECTION_MIN_DELAY, DEFAULT_CONNECTION_MIN_DELAY);
         IndexAttachments indexAttachments = provideIndexAttachments(configuration);
         ImmutableList<Host> hosts = getHosts(configuration);
+
         ReadAliasName readAlias = computeMailboxReadAlias(configuration);
         WriteAliasName writeAlias = computeMailboxWriteAlias(configuration);
         IndexName indexName = computeMailboxIndexName(configuration);
 
+        IndexName quotaRatioIndexName = computeQuotaSearchIndexName(configuration);
+        ReadAliasName quotaSearchReadAlias = computeQuotaSearchReadAlias(configuration);
+        WriteAliasName quotaSearchWriteAlias = computeQuotaSearchWriteAlias(configuration);
+
         return new ElasticSearchConfiguration(
             hosts,
             indexName,
             readAlias,
             writeAlias,
+            quotaRatioIndexName,
+            quotaSearchReadAlias,
+            quotaSearchWriteAlias,
             nbShards,
             nbReplica,
             minDelay,
@@ -124,6 +139,24 @@ public class ElasticSearchConfiguration {
             .orElse(MailboxElasticSearchConstants.DEFAULT_MAILBOX_READ_ALIAS);
     }
 
+    public static IndexName computeQuotaSearchIndexName(PropertiesConfiguration configuration) {
+        return Optional.ofNullable(configuration.getString(ELASTICSEARCH_INDEX_QUOTA_RATIO_NAME))
+            .map(IndexName::new)
+            .orElse(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_INDEX);
+    }
+
+    public static WriteAliasName computeQuotaSearchWriteAlias(PropertiesConfiguration configuration) {
+        return Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_WRITE_QUOTA_RATIO_NAME))
+            .map(WriteAliasName::new)
+            .orElse(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS);
+    }
+
+    public static ReadAliasName computeQuotaSearchReadAlias(PropertiesConfiguration configuration) {
+        return Optional.ofNullable(configuration.getString(ELASTICSEARCH_ALIAS_READ_QUOTA_RATIO_NAME))
+                .map(ReadAliasName::new)
+            .orElse(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS);
+    }
+
     private static IndexAttachments provideIndexAttachments(PropertiesConfiguration configuration) {
         if (configuration.getBoolean(ELASTICSEARCH_INDEX_ATTACHMENTS, DEFAULT_INDEX_ATTACHMENTS)) {
             return IndexAttachments.YES;
@@ -170,19 +203,25 @@ public class ElasticSearchConfiguration {
     private final IndexName indexMailboxName;
     private final ReadAliasName readAliasMailboxName;
     private final WriteAliasName writeAliasMailboxName;
+    private final IndexName indexQuotaRatioName;
+    private final ReadAliasName readAliasQuotaRatioName;
+    private final WriteAliasName writeAliasQuotaRatioName;
     private final int nbShards;
     private final int nbReplica;
     private final int minDelay;
     private final int maxRetries;
     private final IndexAttachments indexAttachment;
 
-    public ElasticSearchConfiguration(ImmutableList<Host> hosts, IndexName indexMailboxName, ReadAliasName readAliasMailboxName,
-                                      WriteAliasName writeAliasMailboxName, int nbShards, int nbReplica, int minDelay,
+    private ElasticSearchConfiguration(ImmutableList<Host> hosts, IndexName indexMailboxName, ReadAliasName readAliasMailboxName,
+                                      WriteAliasName writeAliasMailboxName, IndexName indexQuotaRatioName, ReadAliasName readAliasQuotaRatioName, WriteAliasName writeAliasQuotaRatioName, int nbShards, int nbReplica, int minDelay,
                                       int maxRetries, IndexAttachments indexAttachment) {
         this.hosts = hosts;
         this.indexMailboxName = indexMailboxName;
         this.readAliasMailboxName = readAliasMailboxName;
         this.writeAliasMailboxName = writeAliasMailboxName;
+        this.indexQuotaRatioName = indexQuotaRatioName;
+        this.readAliasQuotaRatioName = readAliasQuotaRatioName;
+        this.writeAliasQuotaRatioName = writeAliasQuotaRatioName;
         this.nbShards = nbShards;
         this.nbReplica = nbReplica;
         this.minDelay = minDelay;
@@ -226,6 +265,18 @@ public class ElasticSearchConfiguration {
         return indexAttachment;
     }
 
+    public IndexName getIndexQuotaRatioName() {
+        return indexQuotaRatioName;
+    }
+
+    public ReadAliasName getReadAliasQuotaRatioName() {
+        return readAliasQuotaRatioName;
+    }
+
+    public WriteAliasName getWriteAliasQuotaRatioName() {
+        return writeAliasQuotaRatioName;
+    }
+
     @Override
     public final boolean equals(Object o) {
         if (o instanceof ElasticSearchConfiguration) {
@@ -239,7 +290,10 @@ public class ElasticSearchConfiguration {
                 && Objects.equals(this.hosts, that.hosts)
                 && Objects.equals(this.indexMailboxName, that.indexMailboxName)
                 && Objects.equals(this.readAliasMailboxName, that.readAliasMailboxName)
-                && Objects.equals(this.writeAliasMailboxName, that.writeAliasMailboxName);
+                && Objects.equals(this.writeAliasMailboxName, that.writeAliasMailboxName)
+                && Objects.equals(this.indexQuotaRatioName, that.indexQuotaRatioName)
+                && Objects.equals(this.readAliasQuotaRatioName, that.readAliasQuotaRatioName)
+                && Objects.equals(this.writeAliasQuotaRatioName, that.writeAliasQuotaRatioName);
         }
         return false;
     }
@@ -247,6 +301,6 @@ public class ElasticSearchConfiguration {
     @Override
     public final int hashCode() {
         return Objects.hash(hosts, indexMailboxName, readAliasMailboxName, writeAliasMailboxName, nbShards,
-            nbReplica, minDelay, maxRetries, indexAttachment);
+            nbReplica, minDelay, maxRetries, indexAttachment, indexQuotaRatioName, readAliasQuotaRatioName, writeAliasMailboxName);
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b5816095/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
index 48e254b..5bfd220 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchMailboxModule.java
@@ -132,7 +132,10 @@ public class ElasticSearchMailboxModule extends AbstractModule {
             configuration.getWriteAliasMailboxName(),
             configuration.getIndexMailboxName());
 
-        QuotaSearchIndexCreationUtil.prepareDefaultClient(client);
+        QuotaSearchIndexCreationUtil.prepareClient(client,
+            configuration.getReadAliasQuotaRatioName(),
+            configuration.getWriteAliasMailboxName(),
+            configuration.getIndexQuotaRatioName());
 
         return client;
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b5816095/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
index 0a10aac..ad9dd6f 100644
--- a/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
+++ b/server/container/guice/cassandra-guice/src/main/java/org/apache/james/modules/mailbox/ElasticSearchQuotaSearcherModule.java
@@ -49,7 +49,7 @@ public class ElasticSearchQuotaSearcherModule extends AbstractModule {
     @Singleton
     public QuotaSearcher provideSearcher(Client client, ElasticSearchConfiguration configuration) {
         return new ElasticSearchQuotaSearcher(client,
-            QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS);
+            configuration.getReadAliasQuotaRatioName());
     }
 
     @Provides
@@ -60,7 +60,7 @@ public class ElasticSearchQuotaSearcherModule extends AbstractModule {
         return new ElasticSearchQuotaMailboxListener(
             new ElasticSearchIndexer(client,
                 executor,
-                QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS,
+                configuration.getWriteAliasMailboxName(),
                 QuotaRatioElasticSearchConstants.QUOTA_RATIO_TYPE),
                 new QuotaRatioToElasticSearchJson());
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/b5816095/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
index e6b13d3..bcaae13 100644
--- a/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
+++ b/server/container/guice/cassandra-guice/src/test/java/org/apache/james/modules/mailbox/ElasticSearchConfigurationTest.java
@@ -28,8 +28,11 @@ import org.apache.commons.configuration.ConfigurationException;
 import org.apache.commons.configuration.PropertiesConfiguration;
 import org.apache.james.backends.es.AliasName;
 import org.apache.james.backends.es.IndexName;
+import org.apache.james.backends.es.ReadAliasName;
+import org.apache.james.backends.es.WriteAliasName;
 import org.apache.james.mailbox.elasticsearch.IndexAttachments;
 import org.apache.james.mailbox.elasticsearch.MailboxElasticSearchConstants;
+import org.apache.james.quota.search.elasticsearch.QuotaRatioElasticSearchConstants;
 import org.apache.james.util.Host;
 import org.junit.Test;
 
@@ -287,6 +290,78 @@ public class ElasticSearchConfigurationTest {
     }
 
     @Test
+    public void getReadAliasQuotaRatioNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.read.quota.ratio.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasQuotaRatioName())
+            .isEqualTo(new ReadAliasName(name));
+    }
+
+    @Test
+    public void getReadAliasQuotaRatioNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getReadAliasQuotaRatioName())
+            .isEqualTo(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS);
+    }
+
+    @Test
+    public void getWriteAliasQuotaRatioNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.alias.write.quota.ratio.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasQuotaRatioName())
+            .isEqualTo(new WriteAliasName(name));
+    }
+
+    @Test
+    public void getWriteAliasQuotaRatioNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getWriteAliasQuotaRatioName())
+            .isEqualTo(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS);
+    }
+
+    @Test
+    public void getIndexQuotaRatioNameShouldReturnConfiguredValue() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        String name = "name";
+        configuration.addProperty("elasticsearch.index.quota.ratio.name", name);
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexQuotaRatioName())
+            .isEqualTo(new IndexName(name));
+    }
+
+    @Test
+    public void getIndexQuotaRatioNameShouldReturnDefaultValueWhenMissing() throws ConfigurationException {
+        PropertiesConfiguration configuration = new PropertiesConfiguration();
+        configuration.addProperty("elasticsearch.hosts", "127.0.0.1");
+
+        ElasticSearchConfiguration elasticSearchConfiguration = ElasticSearchConfiguration.fromProperties(configuration);
+
+        assertThat(elasticSearchConfiguration.getIndexQuotaRatioName())
+            .isEqualTo(QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_INDEX);
+    }
+
+    @Test
     public void getIndexAttachmentShouldReturnConfiguredValueWhenTrue() throws ConfigurationException {
         PropertiesConfiguration configuration = new PropertiesConfiguration();
         configuration.addProperty("elasticsearch.indexAttachments", true);
@@ -377,7 +452,7 @@ public class ElasticSearchConfigurationTest {
     }
 
     @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenNoHostSpecify() throws Exception {
+    public void validateHostsConfigurationOptionsShouldThrowWhenNoHostSpecify() {
         assertThatThrownBy(() ->
             ElasticSearchConfiguration.validateHostsConfigurationOptions(
                 Optional.empty(),
@@ -390,7 +465,7 @@ public class ElasticSearchConfigurationTest {
     }
 
     @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoAndMultiHostSpecified() throws Exception {
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoAndMultiHostSpecified() {
         assertThatThrownBy(() ->
             ElasticSearchConfiguration.validateHostsConfigurationOptions(
                 Optional.of("localhost"),
@@ -401,7 +476,7 @@ public class ElasticSearchConfigurationTest {
     }
 
     @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutPort() throws Exception {
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutPort() {
         assertThatThrownBy(() ->
             ElasticSearchConfiguration.validateHostsConfigurationOptions(
                 Optional.of("localhost"),
@@ -413,7 +488,7 @@ public class ElasticSearchConfigurationTest {
     }
 
     @Test
-    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutAddress() throws Exception {
+    public void validateHostsConfigurationOptionsShouldThrowWhenMonoHostWithoutAddress() {
         assertThatThrownBy(() ->
         ElasticSearchConfiguration.validateHostsConfigurationOptions(
             Optional.empty(),


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


[10/14] james-project git commit: JAMES-2404 Document new endpoint for Quota Search

Posted by bt...@apache.org.
JAMES-2404 Document new endpoint for Quota Search


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

Branch: refs/heads/master
Commit: a7997fef1b34044f0f51a74e550fbf84ed78ad27
Parents: b581609
Author: benwa <bt...@linagora.com>
Authored: Mon May 28 16:47:21 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 src/site/markdown/server/manage-webadmin.md | 69 ++++++++++++++++++++++--
 1 file changed, 66 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/a7997fef/src/site/markdown/server/manage-webadmin.md
----------------------------------------------------------------------
diff --git a/src/site/markdown/server/manage-webadmin.md b/src/site/markdown/server/manage-webadmin.md
index 9702753..5dfc243 100644
--- a/src/site/markdown/server/manage-webadmin.md
+++ b/src/site/markdown/server/manage-webadmin.md
@@ -269,6 +269,7 @@ Response codes:
  - [Getting the quota size for a user](#getting-the-quota-size-for-a-user)
  - [Updating the quota size for a user](#updating-the-quota-size-for-a-user)
  - [Deleting the quota size for a user](#deleting-the-quota-size-for-a-user)
+ - [Searching user by quota ratio](#searching-user-by-quota-ratio)
 
 ### Getting the quota for a user
 
@@ -474,11 +475,73 @@ Response codes:
  - 409: The requested restriction can’t be enforced right now.
  - 500: Internal server error - Something went bad on the server side.
 
+### Searching user by quota ratio
+
+```
+curl -XGET http://ip:port/quota/users?minOccupationRatio=0.8&maxOccupationRatio=0.99&limit=100&offset=200&domain=oppen-paas.org
+```
+
+Will return:
+
+```
+[
+  {
+    "username":"user@open-paas.org",
+    "detail": {
+      "global": {
+        "count":252,
+        "size":242
+      },
+      "domain": {
+        "count":152,
+        "size":142
+      },
+      "user": {
+        "count":52,
+        "size":42
+      },
+      "computed": {
+        "count":52,
+        "size":42
+      },
+      "occupation": {
+        "size":1000,
+        "count":10000,
+        "ratio": {
+          "size":0.8,
+          "count":0.6,
+          "max":0.8
+        }
+      }
+    }
+  },
+  ...
+]
+```
+
+Where:
+
+ - **minOccupationRatio** is a query parameter determining the minimum occupation ratio of users to be returned.
+ - **maxOccupationRatio** is a query parameter determining the maximum occupation ratio of users to be returned.
+ - **domain** is a query parameter determining the domain of users to be returned.
+ - **limit** is a query parameter determining the maximum number of users to be returned.
+ - **offset** is a query parameter determining the number of users to skip.
+
+Please note that users are alphabetically ordered on username.
+
+The response is a list of usernames, with attached quota details as defined [here](#getting-the-quota-for-a-user).
+
+Response codes:
+
+ - 200: List of users had successfully been returned.
+ - 400: Validation issues with parameters
+ - 500: Internal server error - Something went bad on the server side.
+
 ## Administrating quotas by domains
 
  - [Getting the quota for a domain](#getting-the-quota-for-a-domain)
  - [Updating the quota for a domain](#updating-the-quota-for-a-domain)
- - [Getting the quota count for a domain](#getting-the-quota-count-for-addomain)
+ - [Getting the quota count for a domain](#getting-the-quota-count-for-a-domain)
  - [Updating the quota count for a domain](#updating-the-quota-count-for-a-domain)
  - [Deleting the quota count for a domain](#deleting-the-quota-count-for-a-domain)
  - [Getting the quota size for a domain](#getting-the-quota-size-for-a-domain)
@@ -847,8 +910,8 @@ These schema updates can be triggered by webadmin using the Cassandra backend.
 
 Note that currently the progress can be tracked by logs.
 
- - [Retrieving current Cassandra schema version](#retrieving-current-Cassandra-schema-version)
- - [Retrieving latest available Cassandra schema version](#retrieving-latest-available-Cassandra-schema-version)
+ - [Retrieving current Cassandra schema version](#retrieving-current-cassandra-schema-version)
+ - [Retrieving latest available Cassandra schema version](#retrieving-latest-available-cassandra-schema-version)
  - [Upgrading to a specific version](#upgrading-to-a-specific-version)
  - [Upgrading to the latest version](#upgrading-to-the-latest-version)
 


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


[04/14] james-project git commit: JAMES-2404 Introduce UsersQuotaDetailsDTO

Posted by bt...@apache.org.
JAMES-2404 Introduce UsersQuotaDetailsDTO


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

Branch: refs/heads/master
Commit: b0de5a202dcd4dc38201723e7b7f3823b43f01d8
Parents: e5f9d00
Author: Antoine Duprat <ad...@linagora.com>
Authored: Fri May 25 14:49:03 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:52 2018 +0200

----------------------------------------------------------------------
 .../webadmin/dto/UsersQuotaDetailsDTO.java      | 79 ++++++++++++++++++++
 .../webadmin/dto/UsersQuotaDetailsDTOTest.java  | 64 ++++++++++++++++
 2 files changed, 143 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/b0de5a20/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
new file mode 100644
index 0000000..146fc51
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTO.java
@@ -0,0 +1,79 @@
+/****************************************************************
+ * 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.webadmin.dto;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.User;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+
+public class UsersQuotaDetailsDTO {
+
+    private static final String USERNAME = "username";
+
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    public static class Builder {
+        private User user;
+        private QuotaDetailsDTO detail;
+        
+        private Builder() {
+        }
+
+        public Builder user(User user) {
+            this.user = user;
+            return this;
+        }
+
+        public Builder detail(QuotaDetailsDTO detail) {
+            this.detail = detail;
+            return this;
+        }
+
+        public UsersQuotaDetailsDTO build() {
+            Preconditions.checkNotNull(user);
+            Preconditions.checkNotNull(detail);
+            return new UsersQuotaDetailsDTO(user, detail);
+        }
+    }
+
+    private final User user;
+    private final QuotaDetailsDTO detail;
+
+    @VisibleForTesting UsersQuotaDetailsDTO(User user, QuotaDetailsDTO detail) {
+        this.user = user;
+        this.detail = detail;
+    }
+
+    @JsonProperty(USERNAME)
+    public String getUser() throws AddressException {
+        return user.asMailAddress().asPrettyString();
+    }
+
+    public QuotaDetailsDTO getDetail() {
+        return detail;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/b0de5a20/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTOTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTOTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTOTest.java
new file mode 100644
index 0000000..d96915d
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/dto/UsersQuotaDetailsDTOTest.java
@@ -0,0 +1,64 @@
+/****************************************************************
+ * 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.webadmin.dto;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+
+import javax.mail.internet.AddressException;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.quota.QuotaCount;
+import org.apache.james.mailbox.quota.QuotaSize;
+import org.junit.Test;
+
+public class UsersQuotaDetailsDTOTest {
+
+    @Test
+    public void builderShouldThrowWhenUserIsNull() {
+        assertThatThrownBy(() -> UsersQuotaDetailsDTO.builder().build())
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void builderShouldThrowWhenDetailIsNull() {
+        assertThatThrownBy(() -> UsersQuotaDetailsDTO.builder()
+                .user(User.fromUsername("user@domain.org"))
+                .build())
+            .isInstanceOf(NullPointerException.class);
+    }
+
+    @Test
+    public void builderShouldWork() throws AddressException {
+        User user = User.fromUsername("user@domain.org");
+        QuotaDetailsDTO quotaDetailsDTO = QuotaDetailsDTO.builder()
+                .occupation(
+                        Quota.<QuotaSize>builder().used(QuotaSize.size(1)).computedLimit(QuotaSize.size(12)).build(),
+                        Quota.<QuotaCount>builder().used(QuotaCount.count(36)).computedLimit(QuotaCount.count(360)).build())
+                .build();
+        UsersQuotaDetailsDTO usersQuotaDetailsDTO = UsersQuotaDetailsDTO.builder()
+                .user(user)
+                .detail(quotaDetailsDTO)
+                .build();
+
+        assertThat(usersQuotaDetailsDTO.getUser()).isEqualTo(user.asString());
+        assertThat(usersQuotaDetailsDTO.getDetail()).isEqualTo(quotaDetailsDTO);
+    }
+}


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


[11/14] james-project git commit: JAMES-2404 Re-enable some skept assertions

Posted by bt...@apache.org.
JAMES-2404 Re-enable some skept assertions


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

Branch: refs/heads/master
Commit: 9a6fdbe3d68da82665b5bb9d3a1c753f021aa7e3
Parents: 33e94d6
Author: benwa <bt...@linagora.com>
Authored: Tue May 29 09:36:20 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 .../webadmin/routes/GlobalQuotaRoutesTest.java      | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/9a6fdbe3/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
index fd81fcf..d2cf81f 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
@@ -163,7 +163,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
+    public void deleteCountShouldSetQuotaToUnlimited() {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
 
         when()
@@ -270,7 +270,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
+    public void deleteSizeShouldSetQuotaToUnlimited() {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(42));
 
         when()
@@ -321,7 +321,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void getQuotaShouldReturnOnlySizeWhenNoCount() throws Exception {
+    public void getQuotaShouldReturnOnlySizeWhenNoCount() {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(42));
 
         JsonPath jsonPath =
@@ -372,6 +372,7 @@ class GlobalQuotaRoutesTest {
         SoftAssertions softly = new SoftAssertions();
         softly.assertThat(maxQuotaManager.getGlobalMaxMessage()).contains(QuotaCount.count(52));
         softly.assertThat(maxQuotaManager.getGlobalMaxStorage()).contains(QuotaSize.size(42));
+        softly.assertAll();
     }
 
     @Test
@@ -386,10 +387,11 @@ class GlobalQuotaRoutesTest {
         SoftAssertions softly = new SoftAssertions();
         softly.assertThat(maxQuotaManager.getGlobalMaxMessage()).contains(QuotaCount.unlimited());
         softly.assertThat(maxQuotaManager.getGlobalMaxStorage()).contains(QuotaSize.unlimited());
+        softly.assertAll();
     }
 
     @Test
-    public void putQuotaShouldUnsetCountWhenNull() throws Exception {
+    public void putQuotaShouldUnsetCountWhenNull() {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
         given()
             .body("{\"count\":null,\"size\":43}")
@@ -402,7 +404,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetSizeWhenNull() throws Exception {
+    public void putQuotaShouldUnsetSizeWhenNull() {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(44));
         given()
             .body("{\"count\":45,\"size\":null}")
@@ -415,7 +417,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetCountWhenAbsent() throws Exception {
+    public void putQuotaShouldUnsetCountWhenAbsent() {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
         given()
             .body("{\"size\":43}")
@@ -428,7 +430,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetSizeWhenAbsent() throws Exception {
+    public void putQuotaShouldUnsetSizeWhenAbsent() {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(44));
         given()
             .body("{\"count\":45}")


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


[12/14] james-project git commit: JAMES-2404 Fix unstable test

Posted by bt...@apache.org.
JAMES-2404 Fix unstable test


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

Branch: refs/heads/master
Commit: 33e94d69d6821ba02c8a18a0cc61399c0edc2bce
Parents: a7997fe
Author: Antoine Duprat <ad...@linagora.com>
Authored: Mon May 28 14:41:10 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 .../java/org/apache/james/backends/es/DeleteByQueryPerformer.java | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/33e94d69/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
----------------------------------------------------------------------
diff --git a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
index a267b3a..024511b 100644
--- a/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
+++ b/backends-common/elasticsearch/src/main/java/org/apache/james/backends/es/DeleteByQueryPerformer.java
@@ -70,7 +70,8 @@ public class DeleteByQueryPerformer {
                 .setQuery(queryBuilder)
                 .setSize(batchSize))
             .stream()
-            .forEach(searchResponse -> deleteRetrievedIds(client, searchResponse));
+            .map(searchResponse -> deleteRetrievedIds(client, searchResponse))
+            .forEach(ListenableActionFuture::actionGet);
     }
 
     private ListenableActionFuture<BulkResponse> deleteRetrievedIds(Client client, SearchResponse searchResponse) {


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


[09/14] james-project git commit: JAMES-2404 Add more tests for Quota Search REST API

Posted by bt...@apache.org.
JAMES-2404 Add more tests for Quota Search REST API


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

Branch: refs/heads/master
Commit: 350bc6c5a72183e4465b0563a89419ed61afccee
Parents: 110c034
Author: duc <tr...@gmail.com>
Authored: Mon May 28 17:40:14 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:53 2018 +0200

----------------------------------------------------------------------
 .../protocols/webadmin/webadmin-mailbox/pom.xml |   5 +
 .../routes/RestQuotaSearchTestSystem.java       |  75 ---
 .../routes/ScanningQuotaSearchExtension.java    |  87 ++++
 .../ScanningRestQuotaSearchExtension.java       |  87 ----
 .../webadmin/routes/UserQuotaRoutesTest.java    | 486 ++++++++++++++-----
 .../routes/WebAdminQuotaSearchTestSystem.java   |  75 +++
 6 files changed, 528 insertions(+), 287 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index ae32a95..93cfd57 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -138,6 +138,11 @@
             <artifactId>javax.inject</artifactId>
         </dependency>
         <dependency>
+            <groupId>net.javacrumbs.json-unit</groupId>
+            <artifactId>json-unit-fluent</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
             <groupId>org.assertj</groupId>
             <artifactId>assertj-core</artifactId>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
deleted file mode 100644
index fb6001e..0000000
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
+++ /dev/null
@@ -1,75 +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.webadmin.routes;
-
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
-
-import org.apache.james.metrics.api.NoopMetricFactory;
-import org.apache.james.quota.search.QuotaSearchTestSystem;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.apache.james.webadmin.jackson.QuotaModule;
-import org.apache.james.webadmin.service.UserQuotaService;
-import org.apache.james.webadmin.utils.JsonTransformer;
-
-import com.google.common.collect.ImmutableSet;
-import com.jayway.restassured.specification.RequestSpecification;
-
-public class RestQuotaSearchTestSystem {
-    private final QuotaSearchTestSystem quotaSearchTestSystem;
-    private final WebAdminServer webAdminServer;
-    private final RequestSpecification requestSpecBuilder;
-
-    public RestQuotaSearchTestSystem(QuotaSearchTestSystem quotaSearchTestSystem) throws Exception {
-        this.quotaSearchTestSystem = quotaSearchTestSystem;
-
-        UserQuotaService userQuotaService = new UserQuotaService(quotaSearchTestSystem.getMaxQuotaManager(),
-            quotaSearchTestSystem.getQuotaManager(),
-            quotaSearchTestSystem.getQuotaRootResolver(),
-            quotaSearchTestSystem.getQuotaSearcher());
-
-        QuotaModule quotaModule = new QuotaModule();
-        JsonTransformer jsonTransformer = new JsonTransformer(quotaModule);
-        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(quotaSearchTestSystem.getUsersRepository(),
-            userQuotaService, jsonTransformer,
-            ImmutableSet.of(quotaModule));
-
-        this.webAdminServer = WebAdminUtils.createWebAdminServer(
-            new NoopMetricFactory(),
-            userQuotaRoutes);
-        this.webAdminServer.configure(NO_CONFIGURATION);
-        this.webAdminServer.await();
-
-        this.requestSpecBuilder = WebAdminUtils.buildRequestSpecification(webAdminServer)
-            .build();
-    }
-
-    public QuotaSearchTestSystem getQuotaSearchTestSystem() {
-        return quotaSearchTestSystem;
-    }
-
-    public WebAdminServer getWebAdminServer() {
-        return webAdminServer;
-    }
-
-    public RequestSpecification getRequestSpecification() {
-        return requestSpecBuilder;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
new file mode 100644
index 0000000..1907a23
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
@@ -0,0 +1,87 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static org.mockito.Mockito.mock;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
+import org.apache.james.quota.search.scanning.ClauseConverter;
+import org.apache.james.quota.search.scanning.ScanningQuotaSearcher;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+public class ScanningQuotaSearchExtension implements ParameterResolver, BeforeEachCallback, AfterEachCallback {
+    private static final Runnable NO_AWAIT = () -> {};
+
+    private WebAdminQuotaSearchTestSystem restQuotaSearchTestSystem;
+
+    @Override
+    public void beforeEach(ExtensionContext context) {
+        try {
+            InMemoryIntegrationResources.Resources resources = new InMemoryIntegrationResources().createResources(new SimpleGroupMembershipResolver());
+
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
+
+            DNSService dnsService = mock(DNSService.class);
+            MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            usersRepository.setDomainList(domainList);
+
+            QuotaSearchTestSystem quotaSearchTestSystem = new QuotaSearchTestSystem(
+                resources.getMaxQuotaManager(),
+                resources.getMailboxManager(),
+                resources.getQuotaManager(),
+                resources.getQuotaRootResolver(),
+                new ScanningQuotaSearcher(usersRepository,
+                    new ClauseConverter(resources.getQuotaRootResolver(), resources.getQuotaManager())),
+                usersRepository,
+                domainList,
+                resources.getCurrentQuotaManager(),
+                NO_AWAIT);
+
+            restQuotaSearchTestSystem = new WebAdminQuotaSearchTestSystem(quotaSearchTestSystem);
+        } catch (Exception e) {
+            throw new ParameterResolutionException("Error while resolving parameter", e);
+        }
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) {
+        restQuotaSearchTestSystem.getWebAdminServer().destroy();
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType() == WebAdminQuotaSearchTestSystem.class);
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return restQuotaSearchTestSystem;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
deleted file mode 100644
index d7cfcaa..0000000
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
+++ /dev/null
@@ -1,87 +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.webadmin.routes;
-
-import static org.mockito.Mockito.mock;
-
-import org.apache.james.dnsservice.api.DNSService;
-import org.apache.james.domainlist.memory.MemoryDomainList;
-import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
-import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
-import org.apache.james.quota.search.QuotaSearchTestSystem;
-import org.apache.james.quota.search.scanning.ClauseConverter;
-import org.apache.james.quota.search.scanning.ScanningQuotaSearcher;
-import org.apache.james.user.memory.MemoryUsersRepository;
-import org.junit.jupiter.api.extension.AfterEachCallback;
-import org.junit.jupiter.api.extension.BeforeEachCallback;
-import org.junit.jupiter.api.extension.ExtensionContext;
-import org.junit.jupiter.api.extension.ParameterContext;
-import org.junit.jupiter.api.extension.ParameterResolutionException;
-import org.junit.jupiter.api.extension.ParameterResolver;
-
-public class ScanningRestQuotaSearchExtension implements ParameterResolver, BeforeEachCallback, AfterEachCallback {
-    private static final Runnable NO_AWAIT = () -> {};
-
-    private RestQuotaSearchTestSystem restQuotaSearchTestSystem;
-
-    @Override
-    public void afterEach(ExtensionContext context) {
-        restQuotaSearchTestSystem.getWebAdminServer().destroy();
-    }
-
-    @Override
-    public void beforeEach(ExtensionContext context) {
-        try {
-            InMemoryIntegrationResources.Resources resources = new InMemoryIntegrationResources().createResources(new SimpleGroupMembershipResolver());
-
-            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
-
-            DNSService dnsService = mock(DNSService.class);
-            MemoryDomainList domainList = new MemoryDomainList(dnsService);
-            usersRepository.setDomainList(domainList);
-
-            QuotaSearchTestSystem quotaSearchTestSystem = new QuotaSearchTestSystem(
-                resources.getMaxQuotaManager(),
-                resources.getMailboxManager(),
-                resources.getQuotaManager(),
-                resources.getQuotaRootResolver(),
-                new ScanningQuotaSearcher(usersRepository,
-                    new ClauseConverter(resources.getQuotaRootResolver(), resources.getQuotaManager())),
-                usersRepository,
-                domainList,
-                resources.getCurrentQuotaManager(),
-                NO_AWAIT);
-
-            restQuotaSearchTestSystem = new RestQuotaSearchTestSystem(quotaSearchTestSystem);
-        } catch (Exception e) {
-            throw new ParameterResolutionException("Error while resolving parameter", e);
-        }
-    }
-
-    @Override
-    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
-        return (parameterContext.getParameter().getType() == RestQuotaSearchTestSystem.class);
-    }
-
-    @Override
-    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
-        return restQuotaSearchTestSystem;
-    }
-}

http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index b4c4595..694cea4 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -21,8 +21,13 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
+import static com.jayway.restassured.RestAssured.with;
+import static net.javacrumbs.jsonunit.core.Option.IGNORING_ARRAY_ORDER;
+import static net.javacrumbs.jsonunit.fluent.JsonFluentAssert.assertThatJson;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.contains;
 import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.hamcrest.Matchers.equalTo;
 
 import java.io.ByteArrayInputStream;
 import java.nio.charset.StandardCharsets;
@@ -31,7 +36,6 @@ import java.util.Map;
 import org.apache.james.core.Domain;
 import org.apache.james.core.User;
 import org.apache.james.domainlist.api.DomainList;
-import org.apache.james.domainlist.api.DomainListException;
 import org.apache.james.mailbox.MailboxManager;
 import org.apache.james.mailbox.MailboxSession;
 import org.apache.james.mailbox.MessageManager;
@@ -44,7 +48,6 @@ import org.apache.james.mailbox.quota.QuotaSize;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
 import org.apache.james.quota.search.QuotaSearchTestSystem;
 import org.apache.james.user.api.UsersRepository;
-import org.apache.james.user.api.UsersRepositoryException;
 import org.assertj.core.api.SoftAssertions;
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.jupiter.api.BeforeEach;
@@ -67,35 +70,33 @@ class UserQuotaRoutesTest {
     private static final User ESCAPED_BOB = User.fromUsername("bob%40" + PERDU_COM);
     private static final User JOE = User.fromUsername("joe@" + PERDU_COM);
     private static final User JACK = User.fromUsername("jack@" + PERDU_COM);
-    private static final User THE_GUY_WITH_STRANGE_DOMAIN = User.fromUsername("guy@" + STRANGE_ORG);
+    private static final User GUY_WITH_STRANGE_DOMAIN = User.fromUsername("guy@" + STRANGE_ORG);
     private static final String PASSWORD = "secret";
     private static final String COUNT = "count";
     private static final String SIZE = "size";
 
-    interface SetUp {
-        @BeforeEach
-        default void setUp(RestQuotaSearchTestSystem testSystem) throws Exception {
-            DomainList domainList = testSystem.getQuotaSearchTestSystem().getDomainList();
-            domainList.addDomain(Domain.of(PERDU_COM));
-            domainList.addDomain(Domain.of(STRANGE_ORG));
+    @BeforeEach
+    public void setUp(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
+        DomainList domainList = testSystem.getQuotaSearchTestSystem().getDomainList();
+        domainList.addDomain(Domain.of(PERDU_COM));
+        domainList.addDomain(Domain.of(STRANGE_ORG));
 
-            UsersRepository usersRepository = testSystem.getQuotaSearchTestSystem().getUsersRepository();
-            usersRepository.addUser(BOB.asString(), PASSWORD);
-            usersRepository.addUser(JACK.asString(), PASSWORD);
-            usersRepository.addUser(THE_GUY_WITH_STRANGE_DOMAIN.asString(), PASSWORD);
+        UsersRepository usersRepository = testSystem.getQuotaSearchTestSystem().getUsersRepository();
+        usersRepository.addUser(BOB.asString(), PASSWORD);
+        usersRepository.addUser(JACK.asString(), PASSWORD);
+        usersRepository.addUser(GUY_WITH_STRANGE_DOMAIN.asString(), PASSWORD);
 
-            RestAssured.requestSpecification = testSystem.getRequestSpecification();
-            RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
-        }
+        RestAssured.requestSpecification = testSystem.getRequestSpecification();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
     }
 
     interface GetUsersQuotaRouteContract {
 
         @Test
-        default void getUsersQuotaShouldReturnAllUsersWhenNoParameters(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldReturnAllUsersWhenNoParameters(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(50));
 
             testSystem.getQuotaSearchTestSystem().await();
 
@@ -107,19 +108,20 @@ class UserQuotaRoutesTest {
                 .body("username", containsInAnyOrder(
                     BOB.asString(),
                     JACK.asString(),
-                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+                    GUY_WITH_STRANGE_DOMAIN.asString()));
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnDomain(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldFilterOnDomain(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(50));
 
             testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("domain", PERDU_COM)
+            .when()
                 .get("/quota/users")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -130,78 +132,82 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldLimitValues(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldLimitValues(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(50));
 
             testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("limit", 2)
+            .when()
                 .get("/quota/users")
             .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
                     BOB.asString(),
-                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+                    GUY_WITH_STRANGE_DOMAIN.asString()));
         }
 
         @Test
-        default void getUsersQuotaShouldAcceptOffset(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldAcceptOffset(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(50));
 
             testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("offset", 1)
+            .when()
                 .get("/quota/users")
             .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
                     JACK.asString(),
-                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+                    GUY_WITH_STRANGE_DOMAIN.asString()));
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnMinOccupationRatio(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldFilterOnMinOccupationRatio(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
 
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(49));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(51));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(51));
 
             testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("minOccupationRatio", 0.5)
+            .when()
                 .get("/quota/users")
             .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
                     JACK.asString(),
-                    THE_GUY_WITH_STRANGE_DOMAIN.asString()));
+                    GUY_WITH_STRANGE_DOMAIN.asString()));
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnMaxOccupationRatio(RestQuotaSearchTestSystem testSystem) throws Exception {
+        default void getUsersQuotaShouldFilterOnMaxOccupationRatio(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
 
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
             appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(49));
             appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
-            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(51));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(51));
 
             testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("maxOccupationRatio", 0.5)
+            .when()
                 .get("/quota/users")
             .then()
                 .statusCode(HttpStatus.OK_200)
@@ -211,7 +217,223 @@ class UserQuotaRoutesTest {
                     BOB.asString()));
         }
 
-        default void appendMessage(QuotaSearchTestSystem testSystem, User user, MessageManager.AppendCommand appendCommand) throws MailboxException, UsersRepositoryException, DomainListException {
+        @Test
+        default void getUsersQuotaShouldOrderByUsername(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(51));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(49));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
+            given()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .body("username", contains(
+                    BOB.asString(),
+                    GUY_WITH_STRANGE_DOMAIN.asString(),
+                    JACK.asString()));
+        }
+
+        @Test
+        default void minOccupationRatioShouldNotBeNegative() {
+            given()
+                .param("minOccupationRatio", -0.5)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("minOccupationRatio can not be negative"));
+        }
+
+        @Test
+        default void minOccupationRatioShouldAcceptZero() {
+            given()
+                .param("minOccupationRatio", 0)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.OK_200);
+        }
+
+        @Test
+        default void minOccupationRatioShouldNotBeString() {
+            given()
+                .param("minOccupationRatio", "invalid")
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("Can not parse minOccupationRatio"))
+                .body("details", equalTo("For input string: \"invalid\""));
+        }
+
+        @Test
+        default void maxOccupationRatioShouldNotBeNegative() {
+            given()
+                .param("maxOccupationRatio", -0.5)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("maxOccupationRatio can not be negative"));
+        }
+
+        @Test
+        default void maxOccupationRatioShouldAcceptZero() {
+            given()
+                .param("maxOccupationRatio", 0)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.OK_200);
+        }
+
+        @Test
+        default void maxOccupationRatioShouldNotBeString() {
+            given()
+                .param("maxOccupationRatio", "invalid")
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("Can not parse maxOccupationRatio"))
+                .body("details", equalTo("For input string: \"invalid\""));
+        }
+
+        @Test
+        default void limitShouldNotBeNegative() {
+            given()
+                .param("limit", -2)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("limit can not be negative"));
+        }
+
+        @Test
+        default void limitShouldNotBeZero() {
+            given()
+                .param("limit", 0)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("limit can not be equal to zero"));
+        }
+
+        @Test
+        default void limitShouldNotBeString() {
+            given()
+                .param("limit", "invalid")
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("Can not parse limit"))
+                .body("details", equalTo("For input string: \"invalid\""));
+        }
+
+        @Test
+        default void offsetShouldNotBeNegative() {
+            given()
+                .param("offset", -2)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("offset can not be negative"));
+        }
+
+        @Test
+        default void offsetShouldAcceptZero() {
+            given()
+                .param("offset", 0)
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.OK_200);
+        }
+
+        @Test
+        default void offsetShouldNotBeString() {
+            given()
+                .param("offset", "invalid")
+            .when()
+                .get("/quota/users")
+            .then()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .contentType(ContentType.JSON)
+                .body("message", equalTo("Can not parse offset"))
+                .body("details", equalTo("For input string: \"invalid\""));
+        }
+
+        @Test
+        default void getUsersQuotaShouldReturnUserDetails(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(10));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(11));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), GUY_WITH_STRANGE_DOMAIN, withSize(50));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
+            String jsonAsString =
+                with()
+                    .param("minOccupationRatio", 0.5)
+                    .get("/quota/users")
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                .extract()
+                    .body()
+                    .asString();
+
+            assertThatJson(jsonAsString)
+                .when(IGNORING_ARRAY_ORDER)
+                    .isEqualTo("[" +
+                            "    {" +
+                            "        \"detail\": {" +
+                            "            \"global\": {" +
+                            "                \"count\": null," +
+                            "                \"size\": 100" +
+                            "            }," +
+                            "            \"domain\": null," +
+                            "            \"user\": null," +
+                            "            \"computed\": {" +
+                            "                \"count\": null," +
+                            "                \"size\": 100" +
+                            "            }," +
+                            "            \"occupation\": {" +
+                            "                \"size\": 50," +
+                            "                \"count\": 1," +
+                            "                \"ratio\": {" +
+                            "                    \"size\": 0.5," +
+                            "                    \"count\": 0.0," +
+                            "                    \"max\": 0.5" +
+                            "                }" +
+                            "            }" +
+                            "        }," +
+                            "        \"username\": \"guy@strange.org\"" +
+                            "    }" +
+                            "]");
+        }
+
+
+        default void appendMessage(QuotaSearchTestSystem testSystem, User user, MessageManager.AppendCommand appendCommand) throws MailboxException {
             MailboxManager mailboxManager = testSystem.getMailboxManager();
             MailboxSession session = mailboxManager.createSystemSession(user.asString());
 
@@ -228,20 +450,20 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class ScanningGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract, SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class ScanningGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract {
 
     }
 
     @Nested
-    @ExtendWith(ElasticSearchRestQuotaSearchExtension.class)
-    class ElasticSearchGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract, SetUp {
+    @ExtendWith(ElasticSearchQuotaSearchExtension.class)
+    class ElasticSearchGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract {
 
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class GetCount implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class GetCount {
 
         @Test
         void getCountShouldReturnNotFoundWhenUserDoesntExist() {
@@ -260,7 +482,7 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getCountShouldReturnStoredValue(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        void getCountShouldReturnStoredValue(WebAdminQuotaSearchTestSystem testSystem) throws MailboxException {
             int value = 42;
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
@@ -270,7 +492,7 @@ class UserQuotaRoutesTest {
             Long actual =
                 given()
                     .get(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-                    .then()
+                .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
                     .extract()
@@ -281,8 +503,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class GetSize implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class GetSize {
         @Test
         void getSizeShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -300,7 +522,7 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getSizeShouldReturnStoredValue(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        void getSizeShouldReturnStoredValue(WebAdminQuotaSearchTestSystem testSystem) throws MailboxException {
             long value = 42;
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
@@ -322,15 +544,15 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class PutCount implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class PutCount {
         @Test
         void putCountShouldReturnNotFoundWhenUserDoesntExist() {
             given()
                 .body("invalid")
             .when()
                 .put(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
-                .then()
+            .then()
                 .statusCode(HttpStatus.NOT_FOUND_404);
         }
 
@@ -340,13 +562,13 @@ class UserQuotaRoutesTest {
                 .body("35")
             .when()
                 .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString() + "/" + COUNT)
-                .then()
+            .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
         }
 
         @Test
         void putCountShouldRejectInvalid() {
-            Map<String, Object> errors = given()
+            Map<String, Object> errors = with()
                 .body("invalid")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
@@ -365,13 +587,12 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putCountShouldSetToInfiniteWhenMinusOne(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putCountShouldSetToInfiniteWhenMinusOne(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("-1")
-            .when()
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
@@ -381,13 +602,13 @@ class UserQuotaRoutesTest {
 
         @Test
         void putCountShouldRejectNegativeOtherThanMinusOne() {
-            Map<String, Object> errors = given()
+            Map<String, Object> errors = with()
                 .body("-2")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
                 .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
-                .extract()
+            .extract()
                 .body()
                 .jsonPath()
                 .getMap(".");
@@ -399,11 +620,11 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putCountShouldAcceptValidValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putCountShouldAcceptValidValue(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("42")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
@@ -414,11 +635,11 @@ class UserQuotaRoutesTest {
 
         @Test
         @Disabled("no link between quota and mailbox for now")
-        void putCountShouldRejectTooSmallValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putCountShouldRejectTooSmallValue(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("42")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
@@ -429,8 +650,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class PutSize implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class PutSize {
         @Test
         void putSizeAcceptEscapedUsers() {
             given()
@@ -443,7 +664,7 @@ class UserQuotaRoutesTest {
 
         @Test
         void putSizeShouldRejectInvalid() {
-            Map<String, Object> errors = given()
+            Map<String, Object> errors = with()
                 .body("invalid")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
@@ -472,13 +693,12 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putSizeShouldSetToInfiniteWhenMinusOne(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putSizeShouldSetToInfiniteWhenMinusOne(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("-1")
-            .when()
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
@@ -495,7 +715,7 @@ class UserQuotaRoutesTest {
             .then()
                 .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
-                .extract()
+            .extract()
                 .body()
                 .jsonPath()
                 .getMap(".");
@@ -507,13 +727,12 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putSizeShouldAcceptValidValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putSizeShouldAcceptValidValue(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("42")
-            .when()
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
@@ -523,8 +742,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class DeleteCount implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class DeleteCount {
 
         @Test
         void deleteCountShouldReturnNotFoundWhenUserDoesntExist() {
@@ -535,12 +754,12 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void deleteCountShouldSetQuotaToEmpty(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void deleteCountShouldSetQuotaToEmpty(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(42));
 
-            given()
+            with()
                 .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
@@ -550,8 +769,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class DeleteSize implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class DeleteSize {
         @Test
         void deleteSizeShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -561,13 +780,13 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void deleteSizeShouldSetQuotaToEmpty(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void deleteSizeShouldSetQuotaToEmpty(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
 
-            given()
+            with()
                 .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
@@ -577,8 +796,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class GetQuota implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class GetQuota {
         @Test
         void getQuotaShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -588,7 +807,7 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnBothWhenValueSpecified(RestQuotaSearchTestSystem testSystem) throws Exception {
+        public void getQuotaShouldReturnBothWhenValueSpecified(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
@@ -600,12 +819,12 @@ class UserQuotaRoutesTest {
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(52));
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
             SoftAssertions softly = new SoftAssertions();
@@ -617,10 +836,11 @@ class UserQuotaRoutesTest {
             softly.assertThat(jsonPath.getLong("domain." + COUNT)).isEqualTo(23);
             softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
             softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(22);
+            softly.assertAll();
         }
 
         @Test
-        public void getQuotaShouldReturnOccupation(RestQuotaSearchTestSystem testSystem) throws Exception {
+        public void getQuotaShouldReturnOccupation(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
             InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
@@ -630,12 +850,12 @@ class UserQuotaRoutesTest {
             currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
             SoftAssertions softly = new SoftAssertions();
@@ -644,10 +864,11 @@ class UserQuotaRoutesTest {
             softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0.2);
             softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0.5);
             softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0.5);
+            softly.assertAll();
         }
 
         @Test
-        public void getQuotaShouldReturnOccupationWhenUnlimited(RestQuotaSearchTestSystem testSystem) throws Exception {
+        public void getQuotaShouldReturnOccupationWhenUnlimited(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
             InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
@@ -657,12 +878,12 @@ class UserQuotaRoutesTest {
             currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
             SoftAssertions softly = new SoftAssertions();
@@ -671,10 +892,11 @@ class UserQuotaRoutesTest {
             softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0);
             softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0);
             softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0);
+            softly.assertAll();
         }
 
         @Test
-        public void getQuotaShouldReturnOnlySpecifiedValues(RestQuotaSearchTestSystem testSystem) throws Exception {
+        public void getQuotaShouldReturnOnlySpecifiedValues(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
@@ -683,39 +905,40 @@ class UserQuotaRoutesTest {
             maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(52));
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
             SoftAssertions softly = new SoftAssertions();
             softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(1111);
-            softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(52);
-            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(52);
+            softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(18);
+            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(18);
             softly.assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
             softly.assertThat(jsonPath.getObject("domain." + SIZE, Long.class)).isNull();
-            softly.assertThat(jsonPath.getObject("domain." + COUNT, Long.class)).isEqualTo(18);
+            softly.assertThat(jsonPath.getObject("domain." + COUNT, Long.class)).isEqualTo(52);
             softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
             softly.assertThat(jsonPath.getObject("global." + COUNT, Long.class)).isNull();
+            softly.assertAll();
         }
 
         @Test
-        public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined(RestQuotaSearchTestSystem testSystem) throws Exception {
+        public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
 
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
             maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(12));
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
             SoftAssertions softly = new SoftAssertions();
@@ -725,10 +948,11 @@ class UserQuotaRoutesTest {
             softly.assertThat(jsonPath.getObject("domain", Object.class)).isNull();
             softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
             softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(12);
+            softly.assertAll();
         }
 
         @Test
-        void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped(WebAdminQuotaSearchTestSystem testSystem) throws MailboxException {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
@@ -738,35 +962,39 @@ class UserQuotaRoutesTest {
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
-            assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
-            assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
+            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+            softly.assertAll();
         }
 
         @Test
         void getQuotaShouldReturnBothEmptyWhenDefaultValues() {
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
-            assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
-            assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
+            softly.assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+            softly.assertAll();
         }
 
         @Test
-        void getQuotaShouldReturnSizeWhenNoCount(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        void getQuotaShouldReturnSizeWhenNoCount(WebAdminQuotaSearchTestSystem testSystem) throws MailboxException {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
@@ -774,20 +1002,22 @@ class UserQuotaRoutesTest {
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
-            assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
-            assertThat(jsonPath.getObject("user." + COUNT, Long.class)).isNull();
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
+            softly.assertThat(jsonPath.getObject("user." + COUNT, Long.class)).isNull();
+            softly.assertAll();
         }
 
         @Test
-        void getQuotaShouldReturnBothWhenNoSize(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        void getQuotaShouldReturnBothWhenNoSize(WebAdminQuotaSearchTestSystem testSystem) throws MailboxException {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
@@ -796,22 +1026,24 @@ class UserQuotaRoutesTest {
 
 
             JsonPath jsonPath =
-                given()
+                when()
                     .get(QUOTA_USERS + "/" + BOB.asString())
                 .then()
                     .statusCode(HttpStatus.OK_200)
                     .contentType(ContentType.JSON)
-                    .extract()
+                .extract()
                     .jsonPath();
 
-            assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
-            assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
+            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+            softly.assertAll();
         }
     }
 
     @Nested
-    @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class PutQuota implements SetUp {
+    @ExtendWith(ScanningQuotaSearchExtension.class)
+    class PutQuota {
 
         @Test
         void putQuotaShouldReturnNotFoundWhenUserDoesntExist() {
@@ -822,37 +1054,41 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putQuotaShouldUpdateBothQuota(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putQuotaShouldUpdateBothQuota(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("{\"count\":52,\"size\":42}")
                 .put(QUOTA_USERS + "/" + BOB.asString())
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
 
-            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
                 .contains(QuotaCount.count(52));
-            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+            softly.assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
                 .contains(QuotaSize.size(42));
+            softly.assertAll();
         }
 
         @Test
-        void putQuotaShouldUpdateBothQuotaWhenEscaped(RestQuotaSearchTestSystem testSystem) throws Exception {
+        void putQuotaShouldUpdateBothQuotaWhenEscaped(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
             UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
-            given()
+            with()
                 .body("{\"count\":52,\"size\":42}")
                 .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
             .then()
                 .statusCode(HttpStatus.NO_CONTENT_204);
 
-            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
                 .contains(QuotaCount.count(52));
-            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+            softly.assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
                 .contains(QuotaSize.size(42));
+            softly.assertAll();
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/james-project/blob/350bc6c5/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
new file mode 100644
index 0000000..03c16f1
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.jackson.QuotaModule;
+import org.apache.james.webadmin.service.UserQuotaService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+
+import com.google.common.collect.ImmutableSet;
+import com.jayway.restassured.specification.RequestSpecification;
+
+public class WebAdminQuotaSearchTestSystem {
+    private final QuotaSearchTestSystem quotaSearchTestSystem;
+    private final WebAdminServer webAdminServer;
+    private final RequestSpecification requestSpecBuilder;
+
+    public WebAdminQuotaSearchTestSystem(QuotaSearchTestSystem quotaSearchTestSystem) throws Exception {
+        this.quotaSearchTestSystem = quotaSearchTestSystem;
+
+        UserQuotaService userQuotaService = new UserQuotaService(quotaSearchTestSystem.getMaxQuotaManager(),
+            quotaSearchTestSystem.getQuotaManager(),
+            quotaSearchTestSystem.getQuotaRootResolver(),
+            quotaSearchTestSystem.getQuotaSearcher());
+
+        QuotaModule quotaModule = new QuotaModule();
+        JsonTransformer jsonTransformer = new JsonTransformer(quotaModule);
+        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(quotaSearchTestSystem.getUsersRepository(),
+            userQuotaService, jsonTransformer,
+            ImmutableSet.of(quotaModule));
+
+        this.webAdminServer = WebAdminUtils.createWebAdminServer(
+            new NoopMetricFactory(),
+            userQuotaRoutes);
+        this.webAdminServer.configure(NO_CONFIGURATION);
+        this.webAdminServer.await();
+
+        this.requestSpecBuilder = WebAdminUtils.buildRequestSpecification(webAdminServer)
+            .build();
+    }
+
+    public QuotaSearchTestSystem getQuotaSearchTestSystem() {
+        return quotaSearchTestSystem;
+    }
+
+    public WebAdminServer getWebAdminServer() {
+        return webAdminServer;
+    }
+
+    public RequestSpecification getRequestSpecification() {
+        return requestSpecBuilder;
+    }
+}


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


[14/14] james-project git commit: JAMES-2404 Rely on JUNIT-5 extensions in other tests

Posted by bt...@apache.org.
JAMES-2404 Rely on JUNIT-5 extensions in other tests


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

Branch: refs/heads/master
Commit: 3d2a90c61140e850fb85076e7b93942f31a5df69
Parents: 9a6fdbe
Author: benwa <bt...@linagora.com>
Authored: Tue May 29 09:51:03 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:54 2018 +0200

----------------------------------------------------------------------
 .../webadmin/routes/DomainQuotaRoutesTest.java  | 62 +++++-------------
 .../webadmin/routes/GlobalQuotaRoutesTest.java  | 67 +++++++-------------
 .../routes/ScanningQuotaSearchExtension.java    |  2 +
 .../routes/WebAdminQuotaSearchTestSystem.java   | 15 ++++-
 4 files changed, 57 insertions(+), 89 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/3d2a90c6/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
index 1be5ba2..b27c0d6 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/DomainQuotaRoutesTest.java
@@ -21,34 +21,24 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.Map;
 
 import org.apache.james.core.Domain;
-import org.apache.james.dnsservice.api.InMemoryDNSService;
-import org.apache.james.domainlist.memory.MemoryDomainList;
-import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaCount;
 import org.apache.james.mailbox.quota.QuotaSize;
-import org.apache.james.metrics.api.NoopMetricFactory;
-import org.apache.james.user.memory.MemoryUsersRepository;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.apache.james.webadmin.jackson.QuotaModule;
-import org.apache.james.webadmin.service.DomainQuotaService;
-import org.apache.james.webadmin.utils.JsonTransformer;
 import org.eclipse.jetty.http.HttpStatus;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 
-import com.google.common.collect.ImmutableSet;
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.path.json.JsonPath;
 
+@ExtendWith(ScanningQuotaSearchExtension.class)
 class DomainQuotaRoutesTest {
 
     private static final String QUOTA_DOMAINS = "/quota/domains";
@@ -56,34 +46,17 @@ class DomainQuotaRoutesTest {
     private static final Domain TROUVÉ_COM = Domain.of("trouvé.com");
     private static final String COUNT = "count";
     private static final String SIZE = "size";
-    private WebAdminServer webAdminServer;
-    private InMemoryPerUserMaxQuotaManager maxQuotaManager;
+    private MaxQuotaManager maxQuotaManager;
 
     @BeforeEach
-    void setUp() throws Exception {
-        maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
-        MemoryDomainList memoryDomainList = new MemoryDomainList(new InMemoryDNSService());
-        memoryDomainList.setAutoDetect(false);
-        memoryDomainList.setAutoDetectIP(false);
-        memoryDomainList.addDomain(TROUVÉ_COM);
-        DomainQuotaService domainQuotaService = new DomainQuotaService(maxQuotaManager);
-        QuotaModule quotaModule = new QuotaModule();
-        MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
-        DomainQuotaRoutes domainQuotaRoutes = new DomainQuotaRoutes(memoryDomainList, domainQuotaService, usersRepository, new JsonTransformer(quotaModule), ImmutableSet.of(quotaModule));
-        webAdminServer = WebAdminUtils.createWebAdminServer(
-            new NoopMetricFactory(),
-            domainQuotaRoutes);
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
-            .build();
-        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
-    }
+    void setUp(WebAdminQuotaSearchTestSystem testSystem) throws Exception {
+        testSystem.getQuotaSearchTestSystem().getDomainList()
+            .addDomain(TROUVÉ_COM);
+
+        maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
 
-    @AfterEach
-    void stop() {
-        webAdminServer.destroy();
+        RestAssured.requestSpecification = testSystem.getRequestSpecification();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
     }
 
     @Test
@@ -103,7 +76,7 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void getCountShouldReturnStoredValue() {
+    void getCountShouldReturnStoredValue() throws Exception {
         int value = 42;
         maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(value));
 
@@ -200,7 +173,7 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void deleteCountShouldSetQuotaToEmpty() {
+    void deleteCountShouldSetQuotaToEmpty() throws Exception {
         maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(42));
 
         given()
@@ -228,11 +201,10 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void getSizeShouldReturnStoredValue() {
+    void getSizeShouldReturnStoredValue() throws Exception {
         long value = 42;
         maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(value));
 
-
         long quota =
             given()
                 .get(QUOTA_DOMAINS + "/" + TROUVÉ_COM.name() + "/" + SIZE)
@@ -327,7 +299,7 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void deleteSizeShouldSetQuotaToEmpty() {
+    void deleteSizeShouldSetQuotaToEmpty() throws Exception {
         maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(42));
 
         given()
@@ -362,7 +334,7 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void getQuotaShouldReturnSizeWhenNoCount() {
+    void getQuotaShouldReturnSizeWhenNoCount() throws Exception {
         int maxStorage = 42;
         maxQuotaManager.setDomainMaxStorage(TROUVÉ_COM, QuotaSize.size(maxStorage));
 
@@ -380,7 +352,7 @@ class DomainQuotaRoutesTest {
     }
 
     @Test
-    void getQuotaShouldReturnBothWhenNoSize() {
+    void getQuotaShouldReturnBothWhenNoSize() throws Exception {
         int maxMessage = 42;
         maxQuotaManager.setDomainMaxMessage(TROUVÉ_COM, QuotaCount.count(maxMessage));
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/3d2a90c6/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
index d2cf81f..cb3380d 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/GlobalQuotaRoutesTest.java
@@ -21,51 +21,32 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
 
 import java.util.Map;
 
-import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaCount;
 import org.apache.james.mailbox.quota.QuotaSize;
-import org.apache.james.metrics.logger.DefaultMetricFactory;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.apache.james.webadmin.jackson.QuotaModule;
-import org.apache.james.webadmin.service.GlobalQuotaService;
-import org.apache.james.webadmin.utils.JsonTransformer;
 import org.assertj.core.api.SoftAssertions;
 import org.eclipse.jetty.http.HttpStatus;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
 
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.path.json.JsonPath;
 
+@ExtendWith(ScanningQuotaSearchExtension.class)
 class GlobalQuotaRoutesTest {
-
-    private WebAdminServer webAdminServer;
-    private InMemoryPerUserMaxQuotaManager maxQuotaManager;
+    private MaxQuotaManager maxQuotaManager;
 
     @BeforeEach
-    void setUp() throws Exception {
-        maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
-        webAdminServer = WebAdminUtils.createWebAdminServer(
-            new DefaultMetricFactory(),
-            new GlobalQuotaRoutes(new GlobalQuotaService(maxQuotaManager), new JsonTransformer(new QuotaModule())));
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
-            .build();
-    }
+    void setUp(WebAdminQuotaSearchTestSystem testSystem) {
+        RestAssured.requestSpecification = testSystem.getRequestSpecification();
 
-    @AfterEach
-    void stop() {
-        webAdminServer.destroy();
+        maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
     }
 
     @Test
@@ -77,7 +58,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void getCountShouldReturnStoredValue() {
+    void getCountShouldReturnStoredValue() throws Exception {
         int value = 42;
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(value));
 
@@ -138,7 +119,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void putCountShouldHandleMinusOneAsInfinite() {
+    void putCountShouldHandleMinusOneAsInfinite() throws Exception {
         given()
             .body("-1")
         .when()
@@ -151,7 +132,7 @@ class GlobalQuotaRoutesTest {
 
 
     @Test
-    void putCountShouldAcceptValidValue() {
+    void putCountShouldAcceptValidValue() throws Exception {
         given()
             .body("42")
         .when()
@@ -163,7 +144,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void deleteCountShouldSetQuotaToUnlimited() {
+    void deleteCountShouldSetQuotaToUnlimited() throws Exception {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
 
         when()
@@ -183,7 +164,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void getSizeShouldReturnStoredValue() {
+    void getSizeShouldReturnStoredValue() throws Exception {
         long value = 42;
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(value));
 
@@ -224,7 +205,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void putSizeShouldHandleMinusOneAsInfinite() {
+    void putSizeShouldHandleMinusOneAsInfinite() throws Exception {
         given()
             .body("-1")
         .when()
@@ -258,7 +239,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void putSizeShouldAcceptValidValue() {
+    void putSizeShouldAcceptValidValue() throws Exception {
         given()
             .body("42")
         .when()
@@ -270,7 +251,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void deleteSizeShouldSetQuotaToUnlimited() {
+    void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(42));
 
         when()
@@ -282,7 +263,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void getQuotaShouldReturnBothWhenValueSpecified() {
+    void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
         int maxStorage = 42;
         int maxMessage = 52;
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(maxStorage));
@@ -321,7 +302,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void getQuotaShouldReturnOnlySizeWhenNoCount() {
+    void getQuotaShouldReturnOnlySizeWhenNoCount() throws Exception {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(42));
 
         JsonPath jsonPath =
@@ -340,7 +321,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void getQuotaShouldReturnOnlyCountWhenNoSize() {
+    void getQuotaShouldReturnOnlyCountWhenNoSize() throws Exception {
         int maxMessage = 42;
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(maxMessage));
 
@@ -361,7 +342,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void putQuotaShouldUpdateBothQuota() {
+    void putQuotaShouldUpdateBothQuota() throws Exception {
         given()
             .body("{\"count\":52,\"size\":42}")
         .when()
@@ -376,7 +357,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    void putQuotaShouldSetBothQuotaToInfinite() {
+    void putQuotaShouldSetBothQuotaToInfinite() throws Exception {
         given()
             .body("{\"count\":-1,\"size\":-1}")
         .when()
@@ -391,7 +372,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetCountWhenNull() {
+    void putQuotaShouldUnsetCountWhenNull() throws Exception {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
         given()
             .body("{\"count\":null,\"size\":43}")
@@ -404,7 +385,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetSizeWhenNull() {
+    void putQuotaShouldUnsetSizeWhenNull() throws Exception {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(44));
         given()
             .body("{\"count\":45,\"size\":null}")
@@ -417,7 +398,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetCountWhenAbsent() {
+    void putQuotaShouldUnsetCountWhenAbsent() throws Exception {
         maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(42));
         given()
             .body("{\"size\":43}")
@@ -430,7 +411,7 @@ class GlobalQuotaRoutesTest {
     }
 
     @Test
-    public void putQuotaShouldUnsetSizeWhenAbsent() {
+    void putQuotaShouldUnsetSizeWhenAbsent() throws Exception {
         maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(44));
         given()
             .body("{\"count\":45}")

http://git-wip-us.apache.org/repos/asf/james-project/blob/3d2a90c6/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
index 1907a23..b595181 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningQuotaSearchExtension.java
@@ -21,6 +21,7 @@ package org.apache.james.webadmin.routes;
 
 import static org.mockito.Mockito.mock;
 
+import org.apache.commons.configuration.DefaultConfigurationBuilder;
 import org.apache.james.dnsservice.api.DNSService;
 import org.apache.james.domainlist.memory.MemoryDomainList;
 import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
@@ -50,6 +51,7 @@ public class ScanningQuotaSearchExtension implements ParameterResolver, BeforeEa
 
             DNSService dnsService = mock(DNSService.class);
             MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            domainList.configure(new DefaultConfigurationBuilder());
             usersRepository.setDomainList(domainList);
 
             QuotaSearchTestSystem quotaSearchTestSystem = new QuotaSearchTestSystem(

http://git-wip-us.apache.org/repos/asf/james-project/blob/3d2a90c6/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
index 03c16f1..75f8d26 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/WebAdminQuotaSearchTestSystem.java
@@ -26,6 +26,8 @@ import org.apache.james.quota.search.QuotaSearchTestSystem;
 import org.apache.james.webadmin.WebAdminServer;
 import org.apache.james.webadmin.WebAdminUtils;
 import org.apache.james.webadmin.jackson.QuotaModule;
+import org.apache.james.webadmin.service.DomainQuotaService;
+import org.apache.james.webadmin.service.GlobalQuotaService;
 import org.apache.james.webadmin.service.UserQuotaService;
 import org.apache.james.webadmin.utils.JsonTransformer;
 
@@ -50,10 +52,21 @@ public class WebAdminQuotaSearchTestSystem {
         UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(quotaSearchTestSystem.getUsersRepository(),
             userQuotaService, jsonTransformer,
             ImmutableSet.of(quotaModule));
+        DomainQuotaRoutes domainQuotaRoutes = new DomainQuotaRoutes(
+            quotaSearchTestSystem.getDomainList(),
+            new DomainQuotaService(quotaSearchTestSystem.getMaxQuotaManager()),
+            quotaSearchTestSystem.getUsersRepository(),
+            jsonTransformer,
+            ImmutableSet.of(quotaModule));
+        GlobalQuotaRoutes globalQuotaRoutes = new GlobalQuotaRoutes(
+            new GlobalQuotaService(quotaSearchTestSystem.getMaxQuotaManager()),
+            jsonTransformer);
 
         this.webAdminServer = WebAdminUtils.createWebAdminServer(
             new NoopMetricFactory(),
-            userQuotaRoutes);
+            userQuotaRoutes,
+            domainQuotaRoutes,
+            globalQuotaRoutes);
         this.webAdminServer.configure(NO_CONFIGURATION);
         this.webAdminServer.await();
 


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


[13/14] james-project git commit: JAMES-2404 Rename endpoint constant for Users Quota Routes

Posted by bt...@apache.org.
JAMES-2404 Rename endpoint constant for Users Quota Routes


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

Branch: refs/heads/master
Commit: f56c0bbeff19a03aaf060ce68d2725a7ac1f7064
Parents: 3d2a90c
Author: benwa <bt...@linagora.com>
Authored: Tue May 29 09:53:04 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:54 2018 +0200

----------------------------------------------------------------------
 .../org/apache/james/webadmin/routes/UserQuotaRoutes.java    | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/f56c0bbe/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
index a991045..4b8a310 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
@@ -67,7 +67,7 @@ import spark.Request;
 import spark.Service;
 
 @Api(tags = "UserQuota")
-@Path(UserQuotaRoutes.MAIN_QUOTA_ENDPOINT)
+@Path(UserQuotaRoutes.USERS_QUOTA_ENDPOINT)
 @Produces("application/json")
 public class UserQuotaRoutes implements Routes {
 
@@ -75,8 +75,8 @@ public class UserQuotaRoutes implements Routes {
     private static final String MIN_OCCUPATION_RATIO = "minOccupationRatio";
     private static final String MAX_OCCUPATION_RATIO = "maxOccupationRatio";
     private static final String DOMAIN = "domain";
-    static final String MAIN_QUOTA_ENDPOINT = "/quota/users";
-    private static final String QUOTA_ENDPOINT = MAIN_QUOTA_ENDPOINT + "/:" + USER;
+    static final String USERS_QUOTA_ENDPOINT = "/quota/users";
+    private static final String QUOTA_ENDPOINT = USERS_QUOTA_ENDPOINT + "/:" + USER;
     private static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
     private static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
 
@@ -199,7 +199,7 @@ public class UserQuotaRoutes implements Routes {
             @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
     })
     public void defineGetUsersQuota() {
-        service.get(MAIN_QUOTA_ENDPOINT, (request, response) -> {
+        service.get(USERS_QUOTA_ENDPOINT, (request, response) -> {
             QuotaQuery quotaQuery = QuotaQuery.builder()
                 .lessThan(extractQuotaBoundary(request, MAX_OCCUPATION_RATIO))
                 .moreThan(extractQuotaBoundary(request, MIN_OCCUPATION_RATIO))


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


[03/14] james-project git commit: JAMES-2404 Add ElasticSearch test for Quota search REST API

Posted by bt...@apache.org.
JAMES-2404 Add ElasticSearch test for Quota search REST API


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

Branch: refs/heads/master
Commit: 110c034e4c21abade01cab68933f3191178f21e0
Parents: 7da78ab
Author: duc <tr...@gmail.com>
Authored: Mon May 28 16:16:53 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:52 2018 +0200

----------------------------------------------------------------------
 .../protocols/webadmin/webadmin-mailbox/pom.xml |  11 +
 .../ElasticSearchQuotaSearchExtension.java      | 117 +++++++++
 .../webadmin/routes/UserQuotaRoutesTest.java    | 259 +++++++++++++------
 3 files changed, 314 insertions(+), 73 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/110c034e/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index 3e5b6bb..ae32a95 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -77,6 +77,17 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-backends-es</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search-elasticsearch</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-core</artifactId>
             <type>test-jar</type>
             <scope>test</scope>

http://git-wip-us.apache.org/repos/asf/james-project/blob/110c034e/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ElasticSearchQuotaSearchExtension.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ElasticSearchQuotaSearchExtension.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ElasticSearchQuotaSearchExtension.java
new file mode 100644
index 0000000..d9a9e24
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ElasticSearchQuotaSearchExtension.java
@@ -0,0 +1,117 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static org.mockito.Mockito.mock;
+
+import java.util.concurrent.Executors;
+
+import org.apache.james.backends.es.ElasticSearchIndexer;
+import org.apache.james.backends.es.EmbeddedElasticSearch;
+import org.apache.james.backends.es.utils.TestingClientProvider;
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.mock.MockMailboxSession;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
+import org.apache.james.quota.search.elasticsearch.ElasticSearchQuotaSearcher;
+import org.apache.james.quota.search.elasticsearch.QuotaRatioElasticSearchConstants;
+import org.apache.james.quota.search.elasticsearch.QuotaSearchIndexCreationUtil;
+import org.apache.james.quota.search.elasticsearch.events.ElasticSearchQuotaMailboxListener;
+import org.apache.james.quota.search.elasticsearch.json.QuotaRatioToElasticSearchJson;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.elasticsearch.client.Client;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+import org.junit.rules.TemporaryFolder;
+
+public class ElasticSearchQuotaSearchExtension implements ParameterResolver, BeforeEachCallback, AfterEachCallback {
+
+    private WebAdminQuotaSearchTestSystem restQuotaSearchTestSystem;
+    private TemporaryFolder temporaryFolder = new TemporaryFolder();
+    private EmbeddedElasticSearch embeddedElasticSearch = new EmbeddedElasticSearch(temporaryFolder, QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_INDEX);
+
+    @Override
+    public void beforeEach(ExtensionContext context) {
+        try {
+            temporaryFolder.create();
+            embeddedElasticSearch.before();
+
+            Client client = QuotaSearchIndexCreationUtil.prepareDefaultClient(
+                new TestingClientProvider(embeddedElasticSearch.getNode()).get());
+
+            InMemoryIntegrationResources.Resources resources = new InMemoryIntegrationResources().createResources(new SimpleGroupMembershipResolver());
+
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
+
+            DNSService dnsService = mock(DNSService.class);
+            MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            usersRepository.setDomainList(domainList);
+
+            ElasticSearchQuotaMailboxListener listener = new ElasticSearchQuotaMailboxListener(
+                new ElasticSearchIndexer(client, Executors.newSingleThreadExecutor(),
+                    QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_WRITE_ALIAS,
+                    QuotaRatioElasticSearchConstants.QUOTA_RATIO_TYPE),
+                new QuotaRatioToElasticSearchJson());
+
+            resources.getMailboxManager()
+                .addGlobalListener(listener, new MockMailboxSession("ANY"));
+
+            QuotaSearchTestSystem quotaSearchTestSystem = new QuotaSearchTestSystem(
+                resources.getMaxQuotaManager(),
+                resources.getMailboxManager(),
+                resources.getQuotaManager(),
+                resources.getQuotaRootResolver(),
+                new ElasticSearchQuotaSearcher(client,
+                    QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS),
+                usersRepository,
+                domainList,
+                resources.getCurrentQuotaManager(),
+                () -> embeddedElasticSearch.awaitForElasticSearch());
+
+            restQuotaSearchTestSystem = new WebAdminQuotaSearchTestSystem(quotaSearchTestSystem);
+        } catch (Exception e) {
+            throw new ParameterResolutionException("Error while resolving parameter", e);
+        }
+    }
+
+    @Override
+    public void afterEach(ExtensionContext context) {
+        restQuotaSearchTestSystem.getWebAdminServer().destroy();
+
+        embeddedElasticSearch.after();
+        temporaryFolder.delete();
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType() == WebAdminQuotaSearchTestSystem.class);
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return restQuotaSearchTestSystem;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/110c034e/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index 8c7bbcd..b4c4595 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -24,18 +24,27 @@ import static com.jayway.restassured.RestAssured.when;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.hamcrest.Matchers.containsInAnyOrder;
 
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.Map;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.User;
 import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.domainlist.api.DomainListException;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.inmemory.quota.InMemoryCurrentQuotaManager;
+import org.apache.james.mailbox.model.MailboxPath;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaCount;
 import org.apache.james.mailbox.quota.QuotaSize;
 import org.apache.james.mailbox.quota.UserQuotaRootResolver;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
 import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
 import org.assertj.core.api.SoftAssertions;
 import org.eclipse.jetty.http.HttpStatus;
 import org.junit.jupiter.api.BeforeEach;
@@ -44,11 +53,11 @@ import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 
+import com.google.common.base.Strings;
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.path.json.JsonPath;
 
-@ExtendWith(ScanningRestQuotaSearchExtension.class)
 class UserQuotaRoutesTest {
 
     private static final String QUOTA_USERS = "/quota/users";
@@ -62,34 +71,37 @@ class UserQuotaRoutesTest {
     private static final String PASSWORD = "secret";
     private static final String COUNT = "count";
     private static final String SIZE = "size";
-    private MaxQuotaManager maxQuotaManager;
-    private UserQuotaRootResolver userQuotaRootResolver;
-    private InMemoryCurrentQuotaManager currentQuotaManager;
-
-    @BeforeEach
-    void setUp(RestQuotaSearchTestSystem testSystem) throws Exception {
-        DomainList domainList = testSystem.getQuotaSearchTestSystem().getDomainList();
-        domainList.addDomain(Domain.of(PERDU_COM));
-        domainList.addDomain(Domain.of(STRANGE_ORG));
-
-        UsersRepository usersRepository = testSystem.getQuotaSearchTestSystem().getUsersRepository();
-        usersRepository.addUser(BOB.asString(), PASSWORD);
-        usersRepository.addUser(JACK.asString(), PASSWORD);
-        usersRepository.addUser(THE_GUY_WITH_STRANGE_DOMAIN.asString(), PASSWORD);
-
-        RestAssured.requestSpecification = testSystem.getRequestSpecification();
-        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
-
-        maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
-        userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
-        currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
+
+    interface SetUp {
+        @BeforeEach
+        default void setUp(RestQuotaSearchTestSystem testSystem) throws Exception {
+            DomainList domainList = testSystem.getQuotaSearchTestSystem().getDomainList();
+            domainList.addDomain(Domain.of(PERDU_COM));
+            domainList.addDomain(Domain.of(STRANGE_ORG));
+
+            UsersRepository usersRepository = testSystem.getQuotaSearchTestSystem().getUsersRepository();
+            usersRepository.addUser(BOB.asString(), PASSWORD);
+            usersRepository.addUser(JACK.asString(), PASSWORD);
+            usersRepository.addUser(THE_GUY_WITH_STRANGE_DOMAIN.asString(), PASSWORD);
+
+            RestAssured.requestSpecification = testSystem.getRequestSpecification();
+            RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+        }
     }
+
     interface GetUsersQuotaRouteContract {
+
         @Test
-        default void getUsersQuotaShouldReturnAllUsersWhenNoParameters() {
+        default void getUsersQuotaShouldReturnAllUsersWhenNoParameters(RestQuotaSearchTestSystem testSystem) throws Exception {
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
             given()
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -99,11 +111,17 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnDomain() {
+        default void getUsersQuotaShouldFilterOnDomain(RestQuotaSearchTestSystem testSystem) throws Exception {
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
             given()
                 .param("domain", PERDU_COM)
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -112,11 +130,17 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldLimitValues() {
+        default void getUsersQuotaShouldLimitValues(RestQuotaSearchTestSystem testSystem) throws Exception {
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
             given()
                 .param("limit", 2)
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -125,11 +149,17 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldAcceptOffset() {
+        default void getUsersQuotaShouldAcceptOffset(RestQuotaSearchTestSystem testSystem) throws Exception {
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(50));
+
+            testSystem.getQuotaSearchTestSystem().await();
+
             given()
                 .param("offset", 1)
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -138,20 +168,20 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnMinOccupationRatio(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        default void getUsersQuotaShouldFilterOnMinOccupationRatio(RestQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
-            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
-            UserQuotaRootResolver quotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
-            currentQuotaManager.increase(quotaRootResolver.forUser(BOB), 1, 49);
-            currentQuotaManager.increase(quotaRootResolver.forUser(JACK), 1, 50);
-            currentQuotaManager.increase(quotaRootResolver.forUser(THE_GUY_WITH_STRANGE_DOMAIN), 1, 51);
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(49));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(51));
+
+            testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("minOccupationRatio", 0.5)
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -160,20 +190,20 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        default void getUsersQuotaShouldFilterOnMaxOccupationRatio(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+        default void getUsersQuotaShouldFilterOnMaxOccupationRatio(RestQuotaSearchTestSystem testSystem) throws Exception {
             MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
-            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
-            UserQuotaRootResolver quotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(100));
-            currentQuotaManager.increase(quotaRootResolver.forUser(BOB), 1, 49);
-            currentQuotaManager.increase(quotaRootResolver.forUser(JACK), 1, 50);
-            currentQuotaManager.increase(quotaRootResolver.forUser(THE_GUY_WITH_STRANGE_DOMAIN), 1, 51);
+            appendMessage(testSystem.getQuotaSearchTestSystem(), BOB, withSize(49));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), JACK, withSize(50));
+            appendMessage(testSystem.getQuotaSearchTestSystem(), THE_GUY_WITH_STRANGE_DOMAIN, withSize(51));
+
+            testSystem.getQuotaSearchTestSystem().await();
 
             given()
                 .param("maxOccupationRatio", 0.5)
                 .get("/quota/users")
-                .then()
+            .then()
                 .statusCode(HttpStatus.OK_200)
                 .contentType(ContentType.JSON)
                 .body("username", containsInAnyOrder(
@@ -181,16 +211,37 @@ class UserQuotaRoutesTest {
                     BOB.asString()));
         }
 
+        default void appendMessage(QuotaSearchTestSystem testSystem, User user, MessageManager.AppendCommand appendCommand) throws MailboxException, UsersRepositoryException, DomainListException {
+            MailboxManager mailboxManager = testSystem.getMailboxManager();
+            MailboxSession session = mailboxManager.createSystemSession(user.asString());
+
+            MailboxPath mailboxPath = MailboxPath.inbox(session);
+            mailboxManager.createMailbox(mailboxPath, session);
+            mailboxManager.getMailbox(mailboxPath, session)
+                .appendMessage(appendCommand, session);
+        }
+
+        default MessageManager.AppendCommand withSize(int size) {
+            byte[] bytes = Strings.repeat("a", size).getBytes(StandardCharsets.UTF_8);
+            return MessageManager.AppendCommand.from(new ByteArrayInputStream(bytes));
+        }
     }
 
     @Nested
     @ExtendWith(ScanningRestQuotaSearchExtension.class)
-    class ScanningGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract {
+    class ScanningGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract, SetUp {
+
+    }
+
+    @Nested
+    @ExtendWith(ElasticSearchRestQuotaSearchExtension.class)
+    class ElasticSearchGetUsersQuotaRouteTest implements GetUsersQuotaRouteContract, SetUp {
 
     }
 
     @Nested
-    class GetCount {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class GetCount implements SetUp {
 
         @Test
         void getCountShouldReturnNotFoundWhenUserDoesntExist() {
@@ -209,8 +260,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getCountShouldReturnStoredValue() throws MailboxException {
+        void getCountShouldReturnStoredValue(RestQuotaSearchTestSystem testSystem) throws MailboxException {
             int value = 42;
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
 
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(value));
 
@@ -228,7 +281,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class GetSize {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class GetSize implements SetUp {
         @Test
         void getSizeShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -246,8 +300,11 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getSizeShouldReturnStoredValue() throws MailboxException {
+        void getSizeShouldReturnStoredValue(RestQuotaSearchTestSystem testSystem) throws MailboxException {
             long value = 42;
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(value));
 
 
@@ -265,7 +322,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class PutCount {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class PutCount implements SetUp {
         @Test
         void putCountShouldReturnNotFoundWhenUserDoesntExist() {
             given()
@@ -307,7 +365,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putCountShouldSetToInfiniteWhenMinusOne() throws Exception {
+        void putCountShouldSetToInfiniteWhenMinusOne(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("-1")
             .when()
@@ -338,7 +399,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putCountShouldAcceptValidValue() throws Exception {
+        void putCountShouldAcceptValidValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("42")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
@@ -350,7 +414,10 @@ class UserQuotaRoutesTest {
 
         @Test
         @Disabled("no link between quota and mailbox for now")
-        void putCountShouldRejectTooSmallValue() throws Exception {
+        void putCountShouldRejectTooSmallValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("42")
                 .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
@@ -362,7 +429,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class PutSize {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class PutSize implements SetUp {
         @Test
         void putSizeAcceptEscapedUsers() {
             given()
@@ -404,7 +472,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putSizeShouldSetToInfiniteWhenMinusOne() throws Exception {
+        void putSizeShouldSetToInfiniteWhenMinusOne(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("-1")
             .when()
@@ -436,7 +507,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putSizeShouldAcceptValidValue() throws Exception {
+        void putSizeShouldAcceptValidValue(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("42")
             .when()
@@ -449,7 +523,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class DeleteCount {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class DeleteCount implements SetUp {
 
         @Test
         void deleteCountShouldReturnNotFoundWhenUserDoesntExist() {
@@ -460,7 +535,9 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void deleteCountShouldSetQuotaToEmpty() throws Exception {
+        void deleteCountShouldSetQuotaToEmpty(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(42));
 
             given()
@@ -473,7 +550,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class DeleteSize {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class DeleteSize implements SetUp {
         @Test
         void deleteSizeShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -483,7 +561,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void deleteSizeShouldSetQuotaToEmpty() throws Exception {
+        void deleteSizeShouldSetQuotaToEmpty(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
 
             given()
@@ -496,7 +577,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class GetQuota {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class GetQuota implements SetUp {
         @Test
         void getQuotaShouldReturnNotFoundWhenUserDoesntExist() {
             when()
@@ -506,7 +588,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
+        public void getQuotaShouldReturnBothWhenValueSpecified(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
             maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(22));
             maxQuotaManager.setDomainMaxStorage(Domain.of(PERDU_COM), QuotaSize.size(34));
@@ -535,7 +620,11 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnOccupation() throws Exception {
+        public void getQuotaShouldReturnOccupation(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
+
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(80));
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(100));
             currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
@@ -558,7 +647,11 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnOccupationWhenUnlimited() throws Exception {
+        public void getQuotaShouldReturnOccupationWhenUnlimited(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+            InMemoryCurrentQuotaManager currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
+
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.unlimited());
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.unlimited());
             currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
@@ -581,7 +674,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnOnlySpecifiedValues() throws Exception {
+        public void getQuotaShouldReturnOnlySpecifiedValues(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(18));
             maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(52));
@@ -607,7 +703,9 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined() throws Exception {
+        public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+
             maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
             maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(12));
 
@@ -630,7 +728,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped() throws MailboxException {
+        void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             int maxStorage = 42;
             int maxMessage = 52;
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
@@ -665,7 +766,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getQuotaShouldReturnSizeWhenNoCount() throws MailboxException {
+        void getQuotaShouldReturnSizeWhenNoCount(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             int maxStorage = 42;
             maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
 
@@ -683,7 +787,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void getQuotaShouldReturnBothWhenNoSize() throws MailboxException {
+        void getQuotaShouldReturnBothWhenNoSize(RestQuotaSearchTestSystem testSystem) throws MailboxException {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             int maxMessage = 42;
             maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
 
@@ -703,7 +810,8 @@ class UserQuotaRoutesTest {
     }
 
     @Nested
-    class PutQuota {
+    @ExtendWith(ScanningRestQuotaSearchExtension.class)
+    class PutQuota implements SetUp {
 
         @Test
         void putQuotaShouldReturnNotFoundWhenUserDoesntExist() {
@@ -714,7 +822,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putQuotaShouldUpdateBothQuota() throws Exception {
+        void putQuotaShouldUpdateBothQuota(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("{\"count\":52,\"size\":42}")
                 .put(QUOTA_USERS + "/" + BOB.asString())
@@ -728,7 +839,10 @@ class UserQuotaRoutesTest {
         }
 
         @Test
-        void putQuotaShouldUpdateBothQuotaWhenEscaped() throws Exception {
+        void putQuotaShouldUpdateBothQuotaWhenEscaped(RestQuotaSearchTestSystem testSystem) throws Exception {
+            MaxQuotaManager maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+            UserQuotaRootResolver userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+
             given()
                 .body("{\"count\":52,\"size\":42}")
                 .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
@@ -741,5 +855,4 @@ class UserQuotaRoutesTest {
                 .contains(QuotaSize.size(42));
         }
     }
-
 }


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


[02/14] james-project git commit: JAMES-2404 Fix Eclipse warnings

Posted by bt...@apache.org.
JAMES-2404 Fix Eclipse warnings


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

Branch: refs/heads/master
Commit: 2129cba6e98d5e09ec16224457f590a1af5cfa7a
Parents: 0bde59b
Author: Antoine Duprat <ad...@linagora.com>
Authored: Mon May 28 14:29:02 2018 +0200
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:15:36 2018 +0200

----------------------------------------------------------------------
 .../elasticsearch/json/IndexableMessageTest.java | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/2129cba6/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java
----------------------------------------------------------------------
diff --git a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java
index b868b6b..2f4501b 100644
--- a/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java
+++ b/mailbox/elasticsearch/src/test/java/org/apache/james/mailbox/elasticsearch/json/IndexableMessageTest.java
@@ -27,7 +27,6 @@ import static org.mockito.Mockito.when;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.time.ZoneId;
-import java.util.Optional;
 
 import javax.mail.Flags;
 
@@ -48,6 +47,7 @@ import org.apache.james.mailbox.tika.TikaContainer;
 import org.apache.james.mailbox.tika.TikaHttpClientImpl;
 import org.apache.james.mailbox.tika.TikaTextExtractor;
 import org.apache.james.metrics.api.NoopMetricFactory;
+import org.assertj.core.api.iterable.Extractor;
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Test;
@@ -473,11 +473,18 @@ public class IndexableMessageTest {
 
         // Then
         assertThat(indexableMessage.getAttachments())
-            .extracting(MimePart::getTextualBody)
-            .contains(Optional.of("first attachment content"));
-        assertThat(indexableMessage.getAttachments())
-            .extracting(MimePart::getTextualBody)
-            .contains(Optional.of("third attachment content"));
+            .extracting(new TextualBodyExtractor())
+            .contains("first attachment content", TextualBodyExtractor.NO_TEXTUAL_BODY, "third attachment content");
+    }
+
+    private static class TextualBodyExtractor implements Extractor<MimePart, String> {
+
+        public static final String NO_TEXTUAL_BODY = "The textual body is not present";
+
+        @Override
+        public String extract(MimePart input) {
+            return input.getTextualBody().orElse(NO_TEXTUAL_BODY);
+        }
     }
 
     @Test


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


[06/14] james-project git commit: JAMES-2404 Rework User quota routes test

Posted by bt...@apache.org.
JAMES-2404 Rework User quota routes test

 - Rely on an extension
 - Use nested tests for easier navigation


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

Branch: refs/heads/master
Commit: 5c4af30c903e5dc247d8db366d5d4a23b22ba049
Parents: b0de5a2
Author: benwa <bt...@linagora.com>
Authored: Mon May 28 11:35:39 2018 +0700
Committer: Antoine Duprat <ad...@linagora.com>
Committed: Tue May 29 15:32:52 2018 +0200

----------------------------------------------------------------------
 .../manager/InMemoryIntegrationResources.java   |    7 +-
 ...ticSearchQuotaSearchTestSystemExtension.java |    6 +-
 .../MemoryQuotaSearchTestSystemExtension.java   |    7 +-
 mailbox/plugin/quota-search/pom.xml             |    5 +
 .../quota/search/QuotaSearchTestSystem.java     |   23 +-
 pom.xml                                         |    5 +
 .../protocols/webadmin/webadmin-mailbox/pom.xml |   21 +
 .../routes/RestQuotaSearchTestSystem.java       |   75 ++
 .../ScanningRestQuotaSearchExtension.java       |   87 ++
 .../webadmin/routes/UserQuotaRoutesTest.java    | 1024 +++++++++---------
 10 files changed, 734 insertions(+), 526 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
----------------------------------------------------------------------
diff --git a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
index 4b6c9a3..5bc12fe 100644
--- a/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
+++ b/mailbox/memory/src/test/java/org/apache/james/mailbox/inmemory/manager/InMemoryIntegrationResources.java
@@ -34,7 +34,6 @@ import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
 import org.apache.james.mailbox.manager.IntegrationResources;
 import org.apache.james.mailbox.manager.ManagerTestResources;
 import org.apache.james.mailbox.model.MessageId;
-import org.apache.james.mailbox.quota.CurrentQuotaManager;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaRootResolver;
@@ -64,12 +63,12 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
         private final InMemoryMailboxManager mailboxManager;
         private final MaxQuotaManager maxQuotaManager;
         private final QuotaManager quotaManager;
-        private final CurrentQuotaManager currentQuotaManager;
+        private final InMemoryCurrentQuotaManager currentQuotaManager;
         private final DefaultUserQuotaRootResolver quotaRootResolver;
         private final StoreRightManager storeRightManager;
         private final MessageId.Factory messageIdFactory;
 
-        public Resources(InMemoryMailboxManager mailboxManager, MaxQuotaManager maxQuotaManager, QuotaManager quotaManager, CurrentQuotaManager currentQuotaManager, DefaultUserQuotaRootResolver quotaRootResolver, StoreRightManager storeRightManager, MessageId.Factory messageIdFactory) {
+        public Resources(InMemoryMailboxManager mailboxManager, MaxQuotaManager maxQuotaManager, QuotaManager quotaManager, InMemoryCurrentQuotaManager currentQuotaManager, DefaultUserQuotaRootResolver quotaRootResolver, StoreRightManager storeRightManager, MessageId.Factory messageIdFactory) {
             this.mailboxManager = mailboxManager;
             this.maxQuotaManager = maxQuotaManager;
             this.quotaManager = quotaManager;
@@ -95,7 +94,7 @@ public class InMemoryIntegrationResources implements IntegrationResources<StoreM
             return quotaRootResolver;
         }
 
-        public CurrentQuotaManager getCurrentQuotaManager() {
+        public InMemoryCurrentQuotaManager getCurrentQuotaManager() {
             return currentQuotaManager;
         }
 

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearchTestSystemExtension.java
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearchTestSystemExtension.java b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearchTestSystemExtension.java
index 0c45f70..ecefaf7 100644
--- a/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearchTestSystemExtension.java
+++ b/mailbox/plugin/quota-search-elasticsearch/src/test/java/org/apache/james/quota/search/elasticsearch/ElasticSearchQuotaSearchTestSystemExtension.java
@@ -80,9 +80,13 @@ public class ElasticSearchQuotaSearchTestSystemExtension implements ParameterRes
             return new QuotaSearchTestSystem(
                 resources.getMaxQuotaManager(),
                 resources.getMailboxManager(),
+                resources.getQuotaManager(),
+                resources.getQuotaRootResolver(),
                 new ElasticSearchQuotaSearcher(client,
                     QuotaRatioElasticSearchConstants.DEFAULT_QUOTA_RATIO_READ_ALIAS),
-                usersRepository, domainList,
+                usersRepository,
+                domainList,
+                resources.getCurrentQuotaManager(),
                 () -> embeddedElasticSearch.awaitForElasticSearch());
         } catch (Exception e) {
             throw new ParameterResolutionException("Error while resolving parameter", e);

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java
index 27b08d2..e6c8f05 100644
--- a/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java
+++ b/mailbox/plugin/quota-search-scanning/src/test/java/org/apache/james/quota/search/scanning/MemoryQuotaSearchTestSystemExtension.java
@@ -55,9 +55,14 @@ public class MemoryQuotaSearchTestSystemExtension implements ParameterResolver {
             return new QuotaSearchTestSystem(
                 resources.getMaxQuotaManager(),
                 resources.getMailboxManager(),
+                resources.getQuotaManager(),
+                resources.getQuotaRootResolver(),
                 new ScanningQuotaSearcher(usersRepository,
                     new ClauseConverter(resources.getQuotaRootResolver(), resources.getQuotaManager())),
-                usersRepository, domainList, NO_AWAIT);
+                usersRepository,
+                domainList,
+                resources.getCurrentQuotaManager(),
+                NO_AWAIT);
         } catch (Exception e) {
             throw new ParameterResolutionException("Error while resolving parameter", e);
         }

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/mailbox/plugin/quota-search/pom.xml
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search/pom.xml b/mailbox/plugin/quota-search/pom.xml
index 9acb4ff..0d4ab40 100644
--- a/mailbox/plugin/quota-search/pom.xml
+++ b/mailbox/plugin/quota-search/pom.xml
@@ -46,6 +46,11 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-memory</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-core</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/mailbox/plugin/quota-search/src/test/java/org/apache/james/quota/search/QuotaSearchTestSystem.java
----------------------------------------------------------------------
diff --git a/mailbox/plugin/quota-search/src/test/java/org/apache/james/quota/search/QuotaSearchTestSystem.java b/mailbox/plugin/quota-search/src/test/java/org/apache/james/quota/search/QuotaSearchTestSystem.java
index 5710a60..41db1a0 100644
--- a/mailbox/plugin/quota-search/src/test/java/org/apache/james/quota/search/QuotaSearchTestSystem.java
+++ b/mailbox/plugin/quota-search/src/test/java/org/apache/james/quota/search/QuotaSearchTestSystem.java
@@ -21,23 +21,32 @@ package org.apache.james.quota.search;
 
 import org.apache.james.domainlist.api.DomainList;
 import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.inmemory.quota.InMemoryCurrentQuotaManager;
 import org.apache.james.mailbox.quota.MaxQuotaManager;
+import org.apache.james.mailbox.quota.QuotaManager;
+import org.apache.james.mailbox.quota.UserQuotaRootResolver;
 import org.apache.james.user.api.UsersRepository;
 
 public class QuotaSearchTestSystem {
     private final MaxQuotaManager maxQuotaManager;
     private final MailboxManager mailboxManager;
+    private final QuotaManager quotaManager;
+    private final UserQuotaRootResolver quotaRootResolver;
     private final QuotaSearcher quotaSearcher;
     private final UsersRepository usersRepository;
     private final DomainList domainList;
+    private final InMemoryCurrentQuotaManager currentQuotaManager;
     private final Runnable await;
 
-    public QuotaSearchTestSystem(MaxQuotaManager maxQuotaManager, MailboxManager mailboxManager, QuotaSearcher quotaSearcher, UsersRepository usersRepository, DomainList domainList, Runnable await) {
+    public QuotaSearchTestSystem(MaxQuotaManager maxQuotaManager, MailboxManager mailboxManager, QuotaManager quotaManager, UserQuotaRootResolver quotaRootResolver, QuotaSearcher quotaSearcher, UsersRepository usersRepository, DomainList domainList, InMemoryCurrentQuotaManager currentQuotaManager, Runnable await) {
         this.maxQuotaManager = maxQuotaManager;
         this.mailboxManager = mailboxManager;
+        this.quotaManager = quotaManager;
+        this.quotaRootResolver = quotaRootResolver;
         this.quotaSearcher = quotaSearcher;
         this.usersRepository = usersRepository;
         this.domainList = domainList;
+        this.currentQuotaManager = currentQuotaManager;
         this.await = await;
     }
 
@@ -61,6 +70,18 @@ public class QuotaSearchTestSystem {
         return domainList;
     }
 
+    public QuotaManager getQuotaManager() {
+        return quotaManager;
+    }
+
+    public UserQuotaRootResolver getQuotaRootResolver() {
+        return quotaRootResolver;
+    }
+
+    public InMemoryCurrentQuotaManager getCurrentQuotaManager() {
+        return currentQuotaManager;
+    }
+
     public void await() {
         await.run();
     }

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 3ee4ec4..805fb3d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -820,6 +820,11 @@
             </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
+                <artifactId>apache-james-mailbox-quota-search-scanning</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
                 <artifactId>apache-james-mailbox-scanning-search</artifactId>
                 <version>${project.version}</version>
             </dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index 5e12fcf..3e5b6bb 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -62,6 +62,27 @@
         </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>apache-james-mailbox-quota-search-scanning</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>james-core</artifactId>
+            <type>test-jar</type>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
             <artifactId>james-server-data-api</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
new file mode 100644
index 0000000..fb6001e
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/RestQuotaSearchTestSystem.java
@@ -0,0 +1,75 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.jackson.QuotaModule;
+import org.apache.james.webadmin.service.UserQuotaService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+
+import com.google.common.collect.ImmutableSet;
+import com.jayway.restassured.specification.RequestSpecification;
+
+public class RestQuotaSearchTestSystem {
+    private final QuotaSearchTestSystem quotaSearchTestSystem;
+    private final WebAdminServer webAdminServer;
+    private final RequestSpecification requestSpecBuilder;
+
+    public RestQuotaSearchTestSystem(QuotaSearchTestSystem quotaSearchTestSystem) throws Exception {
+        this.quotaSearchTestSystem = quotaSearchTestSystem;
+
+        UserQuotaService userQuotaService = new UserQuotaService(quotaSearchTestSystem.getMaxQuotaManager(),
+            quotaSearchTestSystem.getQuotaManager(),
+            quotaSearchTestSystem.getQuotaRootResolver(),
+            quotaSearchTestSystem.getQuotaSearcher());
+
+        QuotaModule quotaModule = new QuotaModule();
+        JsonTransformer jsonTransformer = new JsonTransformer(quotaModule);
+        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(quotaSearchTestSystem.getUsersRepository(),
+            userQuotaService, jsonTransformer,
+            ImmutableSet.of(quotaModule));
+
+        this.webAdminServer = WebAdminUtils.createWebAdminServer(
+            new NoopMetricFactory(),
+            userQuotaRoutes);
+        this.webAdminServer.configure(NO_CONFIGURATION);
+        this.webAdminServer.await();
+
+        this.requestSpecBuilder = WebAdminUtils.buildRequestSpecification(webAdminServer)
+            .build();
+    }
+
+    public QuotaSearchTestSystem getQuotaSearchTestSystem() {
+        return quotaSearchTestSystem;
+    }
+
+    public WebAdminServer getWebAdminServer() {
+        return webAdminServer;
+    }
+
+    public RequestSpecification getRequestSpecification() {
+        return requestSpecBuilder;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
new file mode 100644
index 0000000..d7cfcaa
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ScanningRestQuotaSearchExtension.java
@@ -0,0 +1,87 @@
+/****************************************************************
+ * 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.webadmin.routes;
+
+import static org.mockito.Mockito.mock;
+
+import org.apache.james.dnsservice.api.DNSService;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.quota.search.QuotaSearchTestSystem;
+import org.apache.james.quota.search.scanning.ClauseConverter;
+import org.apache.james.quota.search.scanning.ScanningQuotaSearcher;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.junit.jupiter.api.extension.AfterEachCallback;
+import org.junit.jupiter.api.extension.BeforeEachCallback;
+import org.junit.jupiter.api.extension.ExtensionContext;
+import org.junit.jupiter.api.extension.ParameterContext;
+import org.junit.jupiter.api.extension.ParameterResolutionException;
+import org.junit.jupiter.api.extension.ParameterResolver;
+
+public class ScanningRestQuotaSearchExtension implements ParameterResolver, BeforeEachCallback, AfterEachCallback {
+    private static final Runnable NO_AWAIT = () -> {};
+
+    private RestQuotaSearchTestSystem restQuotaSearchTestSystem;
+
+    @Override
+    public void afterEach(ExtensionContext context) {
+        restQuotaSearchTestSystem.getWebAdminServer().destroy();
+    }
+
+    @Override
+    public void beforeEach(ExtensionContext context) {
+        try {
+            InMemoryIntegrationResources.Resources resources = new InMemoryIntegrationResources().createResources(new SimpleGroupMembershipResolver());
+
+            MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
+
+            DNSService dnsService = mock(DNSService.class);
+            MemoryDomainList domainList = new MemoryDomainList(dnsService);
+            usersRepository.setDomainList(domainList);
+
+            QuotaSearchTestSystem quotaSearchTestSystem = new QuotaSearchTestSystem(
+                resources.getMaxQuotaManager(),
+                resources.getMailboxManager(),
+                resources.getQuotaManager(),
+                resources.getQuotaRootResolver(),
+                new ScanningQuotaSearcher(usersRepository,
+                    new ClauseConverter(resources.getQuotaRootResolver(), resources.getQuotaManager())),
+                usersRepository,
+                domainList,
+                resources.getCurrentQuotaManager(),
+                NO_AWAIT);
+
+            restQuotaSearchTestSystem = new RestQuotaSearchTestSystem(quotaSearchTestSystem);
+        } catch (Exception e) {
+            throw new ParameterResolutionException("Error while resolving parameter", e);
+        }
+    }
+
+    @Override
+    public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return (parameterContext.getParameter().getType() == RestQuotaSearchTestSystem.class);
+    }
+
+    @Override
+    public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
+        return restQuotaSearchTestSystem;
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/5c4af30c/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
index 7c4dd85..4373342 100644
--- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -21,634 +21,620 @@ package org.apache.james.webadmin.routes;
 
 import static com.jayway.restassured.RestAssured.given;
 import static com.jayway.restassured.RestAssured.when;
-import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
 import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
 
 import java.util.Map;
 
 import org.apache.james.core.Domain;
 import org.apache.james.core.User;
-import org.apache.james.dnsservice.api.InMemoryDNSService;
-import org.apache.james.domainlist.memory.MemoryDomainList;
-import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
-import org.apache.james.mailbox.quota.CurrentQuotaManager;
+import org.apache.james.domainlist.api.DomainList;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.inmemory.quota.InMemoryCurrentQuotaManager;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
 import org.apache.james.mailbox.quota.QuotaCount;
-import org.apache.james.mailbox.quota.QuotaManager;
 import org.apache.james.mailbox.quota.QuotaSize;
-import org.apache.james.mailbox.store.MailboxSessionMapperFactory;
-import org.apache.james.mailbox.store.quota.DefaultUserQuotaRootResolver;
-import org.apache.james.mailbox.store.quota.StoreQuotaManager;
-import org.apache.james.metrics.api.NoopMetricFactory;
-import org.apache.james.user.memory.MemoryUsersRepository;
-import org.apache.james.webadmin.WebAdminServer;
-import org.apache.james.webadmin.WebAdminUtils;
-import org.apache.james.webadmin.jackson.QuotaModule;
-import org.apache.james.webadmin.service.UserQuotaService;
-import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.james.mailbox.quota.UserQuotaRootResolver;
+import org.apache.james.user.api.UsersRepository;
 import org.assertj.core.api.SoftAssertions;
 import org.eclipse.jetty.http.HttpStatus;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
 import org.junit.jupiter.api.Test;
-import org.mockito.Mockito;
+import org.junit.jupiter.api.extension.ExtendWith;
 
-import com.google.common.collect.ImmutableSet;
 import com.jayway.restassured.RestAssured;
 import com.jayway.restassured.http.ContentType;
 import com.jayway.restassured.path.json.JsonPath;
 
+@ExtendWith(ScanningRestQuotaSearchExtension.class)
 class UserQuotaRoutesTest {
 
     private static final String QUOTA_USERS = "/quota/users";
     private static final String PERDU_COM = "perdu.com";
+    private static final String STRANGE_ORG = "strange.org";
     private static final User BOB = User.fromUsername("bob@" + PERDU_COM);
     private static final User ESCAPED_BOB = User.fromUsername("bob%40" + PERDU_COM);
     private static final User JOE = User.fromUsername("joe@" + PERDU_COM);
+    private static final User JACK = User.fromUsername("jack@" + PERDU_COM);
+    private static final User THE_GUY_WITH_STRANGE_DOMAIN = User.fromUsername("guy@" + STRANGE_ORG);
     private static final String PASSWORD = "secret";
     private static final String COUNT = "count";
     private static final String SIZE = "size";
-    private WebAdminServer webAdminServer;
-    private InMemoryPerUserMaxQuotaManager maxQuotaManager;
-    private DefaultUserQuotaRootResolver userQuotaRootResolver;
-    private CurrentQuotaManager currentQuotaManager;
+    private MaxQuotaManager maxQuotaManager;
+    private UserQuotaRootResolver userQuotaRootResolver;
+    private InMemoryCurrentQuotaManager currentQuotaManager;
 
     @BeforeEach
-    void setUp() throws Exception {
-        maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
-        MemoryDomainList memoryDomainList = new MemoryDomainList(new InMemoryDNSService());
-        memoryDomainList.setAutoDetect(false);
-        memoryDomainList.addDomain(Domain.of(PERDU_COM));
-        MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting();
-        usersRepository.setDomainList(memoryDomainList);
+    void setUp(RestQuotaSearchTestSystem testSystem) throws Exception {
+        DomainList domainList = testSystem.getQuotaSearchTestSystem().getDomainList();
+        domainList.addDomain(Domain.of(PERDU_COM));
+        domainList.addDomain(Domain.of(STRANGE_ORG));
+
+        UsersRepository usersRepository = testSystem.getQuotaSearchTestSystem().getUsersRepository();
         usersRepository.addUser(BOB.asString(), PASSWORD);
-        MailboxSessionMapperFactory factory = null;
-        userQuotaRootResolver = new DefaultUserQuotaRootResolver(factory);
-
-        currentQuotaManager = mock(CurrentQuotaManager.class);
-        Mockito.when(currentQuotaManager.getCurrentMessageCount(any())).thenReturn(QuotaCount.count(0));
-        Mockito.when(currentQuotaManager.getCurrentStorage(any())).thenReturn(QuotaSize.size(0));
-
-        QuotaManager quotaManager = new StoreQuotaManager(currentQuotaManager, maxQuotaManager);
-        UserQuotaService userQuotaService = new UserQuotaService(maxQuotaManager, quotaManager, userQuotaRootResolver);
-        QuotaModule quotaModule = new QuotaModule();
-        UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(usersRepository, userQuotaService, new JsonTransformer(quotaModule), ImmutableSet.of(quotaModule));
-        webAdminServer = WebAdminUtils.createWebAdminServer(
-            new NoopMetricFactory(),
-            userQuotaRoutes);
-        webAdminServer.configure(NO_CONFIGURATION);
-        webAdminServer.await();
-
-        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
-            .build();
-        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
-    }
+        usersRepository.addUser(JACK.asString(), PASSWORD);
+        usersRepository.addUser(THE_GUY_WITH_STRANGE_DOMAIN.asString(), PASSWORD);
 
-    @AfterEach
-    void stop() {
-        webAdminServer.destroy();
-    }
+        RestAssured.requestSpecification = testSystem.getRequestSpecification();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
 
-    @Test
-    void getCountShouldReturnNotFoundWhenUserDoesntExist() {
-        when()
-            .get(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
+        maxQuotaManager = testSystem.getQuotaSearchTestSystem().getMaxQuotaManager();
+        userQuotaRootResolver = testSystem.getQuotaSearchTestSystem().getQuotaRootResolver();
+        currentQuotaManager = testSystem.getQuotaSearchTestSystem().getCurrentQuotaManager();
     }
 
-    @Test
-    void getCountShouldReturnNoContentByDefault() {
-        given()
-            .get(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-    }
+    @Nested
+    class GetCount {
 
-    @Test
-    void getCountShouldReturnStoredValue() {
-        int value = 42;
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(value));
+        @Test
+        void getCountShouldReturnNotFoundWhenUserDoesntExist() {
+            when()
+                .get(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
 
-        Long actual =
+        @Test
+        void getCountShouldReturnNoContentByDefault() {
             given()
                 .get(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
 
-        assertThat(actual).isEqualTo(value);
-    }
+        @Test
+        void getCountShouldReturnStoredValue() throws MailboxException {
+            int value = 42;
 
-    @Test
-    void putCountShouldReturnNotFoundWhenUserDoesntExist() {
-        given()
-            .body("invalid")
-        .when()
-            .put(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
-    }
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(value));
 
-    @Test
-    void putCountShouldAcceptEscapedUsers() {
-        given()
-            .body("35")
-        .when()
-            .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-    }
+            Long actual =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
+                    .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .as(Long.class);
 
-    @Test
-    void putCountSizeAcceptEscapedUsers() {
-        given()
-            .body("36")
-        .when()
-            .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
+            assertThat(actual).isEqualTo(value);
+        }
     }
 
-    @Test
-    void putCountShouldRejectInvalid() {
-        Map<String, Object> errors = given()
-            .body("invalid")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.BAD_REQUEST_400)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
-            .jsonPath()
-            .getMap(".");
-
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
-            .containsEntry("details", "For input string: \"invalid\"");
-    }
-
-    @Test
-    void putCountShouldSetToInfiniteWhenMinusOne() throws Exception {
-        given()
-            .body("-1")
-        .when()
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).contains(QuotaCount.unlimited());
-    }
-
-    @Test
-    void putCountShouldRejectNegativeOtherThanMinusOne() {
-        Map<String, Object> errors = given()
-            .body("-2")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.BAD_REQUEST_400)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
-            .jsonPath()
-            .getMap(".");
-
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
-    }
-
-    @Test
-    void putCountShouldAcceptValidValue() throws Exception {
-        given()
-            .body("42")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).contains(QuotaCount.count(42));
-    }
-
-    @Test
-    @Disabled("no link between quota and mailbox for now")
-    void putCountShouldRejectTooSmallValue() throws Exception {
-        given()
-            .body("42")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-            .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).isEqualTo(42);
-    }
-
-    @Test
-    void deleteCountShouldReturnNotFoundWhenUserDoesntExist() {
-        when()
-            .delete(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
-    }
-
-
-    @Test
-    void deleteCountShouldSetQuotaToEmpty() throws Exception {
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(42));
-
-        given()
-            .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).isEmpty();
-    }
-
-    @Test
-    void getSizeShouldReturnNotFoundWhenUserDoesntExist() {
+    @Nested
+    class GetSize {
+        @Test
+        void getSizeShouldReturnNotFoundWhenUserDoesntExist() {
             when()
                 .get(QUOTA_USERS + "/" + JOE.asString() + "/" + SIZE)
             .then()
                 .statusCode(HttpStatus.NOT_FOUND_404);
-    }
+        }
 
-    @Test
-    void getSizeShouldReturnNoContentByDefault() {
-        when()
-            .get(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-    }
-
-    @Test
-    void getSizeShouldReturnStoredValue() {
-        long value = 42;
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(value));
-
-
-        long quota =
-            given()
+        @Test
+        void getSizeShouldReturnNoContentByDefault() {
+            when()
                 .get(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .as(Long.class);
-
-        assertThat(quota).isEqualTo(value);
-    }
-
-    @Test
-    void putSizeShouldRejectInvalid() {
-        Map<String, Object> errors = given()
-            .body("invalid")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.BAD_REQUEST_400)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
-            .jsonPath()
-            .getMap(".");
-
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
-            .containsEntry("details", "For input string: \"invalid\"");
-    }
-
-    @Test
-    void putSizeShouldReturnNotFoundWhenUserDoesntExist() {
-        given()
-            .body("123")
-        .when()
-            .put(QUOTA_USERS + "/" + JOE.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
-    }
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
 
-    @Test
-    void putSizeShouldSetToInfiniteWhenMinusOne() throws Exception {
-        given()
-            .body("-1")
-        .when()
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
-            .contains(QuotaSize.unlimited());
-    }
-
-    @Test
-    void putSizeShouldRejectNegativeOtherThanMinusOne() {
-        Map<String, Object> errors = given()
-            .body("-2")
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.BAD_REQUEST_400)
-            .contentType(ContentType.JSON)
-            .extract()
-            .body()
-            .jsonPath()
-            .getMap(".");
-
-        assertThat(errors)
-            .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
-            .containsEntry("type", "InvalidArgument")
-            .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
-    }
+        @Test
+        void getSizeShouldReturnStoredValue() throws MailboxException {
+            long value = 42;
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(value));
 
-    @Test
-    void putSizeShouldAcceptValidValue() throws Exception {
-        given()
-            .body("42")
-        .when()
-            .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB))).contains(QuotaSize.size(42));
-    }
+            long quota =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .as(Long.class);
 
-    @Test
-    void deleteSizeShouldReturnNotFoundWhenUserDoesntExist() {
-        when()
-            .delete(QUOTA_USERS + "/" + JOE.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
+            assertThat(quota).isEqualTo(value);
+        }
     }
 
-    @Test
-    void deleteSizeShouldSetQuotaToEmpty() throws Exception {
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
-
-        given()
-            .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB))).isEmpty();
-    }
-
-    @Test
-    void getQuotaShouldReturnNotFoundWhenUserDoesntExist() {
-        when()
-            .get(QUOTA_USERS + "/" + JOE.asString())
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
-    }
-
-    @Test
-    public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
-        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
-        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(22));
-        maxQuotaManager.setDomainMaxStorage(Domain.of(PERDU_COM), QuotaSize.size(34));
-        maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(23));
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(52));
+    @Nested
+    class PutCount {
+        @Test
+        void putCountShouldReturnNotFoundWhenUserDoesntExist() {
+            given()
+                .body("invalid")
+            .when()
+                .put(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
+                .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
 
-        JsonPath jsonPath =
+        @Test
+        void putCountShouldAcceptEscapedUsers() {
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .body("35")
+            .when()
+                .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString() + "/" + COUNT)
+                .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
+
+        @Test
+        void putCountShouldRejectInvalid() {
+            Map<String, Object> errors = given()
+                .body("invalid")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
+                .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
                 .extract()
-                .jsonPath();
-
-        SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(42);
-        softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(52);
-        softly.assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(42);
-        softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(52);
-        softly.assertThat(jsonPath.getLong("domain." + SIZE)).isEqualTo(34);
-        softly.assertThat(jsonPath.getLong("domain." + COUNT)).isEqualTo(23);
-        softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
-        softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(22);
-    }
-
-    @Test
-    public void getQuotaShouldReturnOccupation() throws Exception {
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(80));
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(100));
-        Mockito.when(currentQuotaManager.getCurrentStorage(any())).thenReturn(QuotaSize.size(40));
-        Mockito.when(currentQuotaManager.getCurrentMessageCount(any())).thenReturn(QuotaCount.count(20));
-
-        JsonPath jsonPath =
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
+                .containsEntry("details", "For input string: \"invalid\"");
+        }
+
+        @Test
+        void putCountShouldSetToInfiniteWhenMinusOne() throws Exception {
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .body("-1")
+            .when()
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .jsonPath();
-
-        SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(jsonPath.getLong("occupation.count")).isEqualTo(20);
-        softly.assertThat(jsonPath.getLong("occupation.size")).isEqualTo(40);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0.2);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0.5);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0.5);
-    }
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-    @Test
-    public void getQuotaShouldReturnOccupationWhenUnlimited() throws Exception {
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.unlimited());
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.unlimited());
-        Mockito.when(currentQuotaManager.getCurrentStorage(any())).thenReturn(QuotaSize.size(40));
-        Mockito.when(currentQuotaManager.getCurrentMessageCount(any())).thenReturn(QuotaCount.count(20));
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).contains(QuotaCount.unlimited());
+        }
 
-        JsonPath jsonPath =
-            given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+        @Test
+        void putCountShouldRejectNegativeOtherThanMinusOne() {
+            Map<String, Object> errors = given()
+                .body("-2")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
+                .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
                 .extract()
-                .jsonPath();
-
-        SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(jsonPath.getLong("occupation.count")).isEqualTo(20);
-        softly.assertThat(jsonPath.getLong("occupation.size")).isEqualTo(40);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0);
-        softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0);
-    }
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
+        }
+
+        @Test
+        void putCountShouldAcceptValidValue() throws Exception {
+            given()
+                .body("42")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-    @Test
-    public void getQuotaShouldReturnOnlySpecifiedValues() throws Exception {
-        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(18));
-        maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(52));
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).contains(QuotaCount.count(42));
+        }
 
-        JsonPath jsonPath =
+        @Test
+        @Disabled("no link between quota and mailbox for now")
+        void putCountShouldRejectTooSmallValue() throws Exception {
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .body("42")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .jsonPath();
-
-        SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(1111);
-        softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(52);
-        softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(52);
-        softly.assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
-        softly.assertThat(jsonPath.getObject("domain." + SIZE, Long.class)).isNull();
-        softly.assertThat(jsonPath.getObject("domain." + COUNT, Long.class)).isEqualTo(18);
-        softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
-        softly.assertThat(jsonPath.getObject("global." + COUNT, Long.class)).isNull();
-    }
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-    @Test
-    public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined() throws Exception {
-        maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
-        maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(12));
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).isEqualTo(42);
+        }
+    }
 
-        JsonPath jsonPath =
+    @Nested
+    class PutSize {
+        @Test
+        void putSizeAcceptEscapedUsers() {
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .body("36")
+            .when()
+                .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString() + "/" + SIZE)
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
+        }
+
+        @Test
+        void putSizeShouldRejectInvalid() {
+            Map<String, Object> errors = given()
+                .body("invalid")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
-                .statusCode(HttpStatus.OK_200)
+                .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
                 .extract()
-                .jsonPath();
-
-        SoftAssertions softly = new SoftAssertions();
-        softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(1111);
-        softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(12);
-        softly.assertThat(jsonPath.getObject("user", Object.class)).isNull();
-        softly.assertThat(jsonPath.getObject("domain", Object.class)).isNull();
-        softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
-        softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(12);
-    }
-
-    @Test
-    void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped() {
-        int maxStorage = 42;
-        int maxMessage = 52;
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1")
+                .containsEntry("details", "For input string: \"invalid\"");
+        }
+
+        @Test
+        void putSizeShouldReturnNotFoundWhenUserDoesntExist() {
+            given()
+                .body("123")
+            .when()
+                .put(QUOTA_USERS + "/" + JOE.asString() + "/" + SIZE)
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
 
-        JsonPath jsonPath =
+        @Test
+        void putSizeShouldSetToInfiniteWhenMinusOne() throws Exception {
             given()
-                .get(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
+                .body("-1")
+            .when()
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .jsonPath();
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
-        assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
-    }
+            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaSize.unlimited());
+        }
 
-    @Test
-    void getQuotaShouldReturnBothEmptyWhenDefaultValues() {
-        JsonPath jsonPath =
-            given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+        @Test
+        void putSizeShouldRejectNegativeOtherThanMinusOne() {
+            Map<String, Object> errors = given()
+                .body("-2")
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
-                .statusCode(HttpStatus.OK_200)
+                .statusCode(HttpStatus.BAD_REQUEST_400)
                 .contentType(ContentType.JSON)
                 .extract()
-                .jsonPath();
+                .body()
+                .jsonPath()
+                .getMap(".");
+
+            assertThat(errors)
+                .containsEntry("statusCode", HttpStatus.BAD_REQUEST_400)
+                .containsEntry("type", "InvalidArgument")
+                .containsEntry("message", "Invalid quota. Need to be an integer value greater or equal to -1");
+        }
+
+        @Test
+        void putSizeShouldAcceptValidValue() throws Exception {
+            given()
+                .body("42")
+            .when()
+                .put(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
-        assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB))).contains(QuotaSize.size(42));
+        }
     }
 
-    @Test
-    void getQuotaShouldReturnSizeWhenNoCount() {
-        int maxStorage = 42;
-        maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
+    @Nested
+    class DeleteCount {
+
+        @Test
+        void deleteCountShouldReturnNotFoundWhenUserDoesntExist() {
+            when()
+                .delete(QUOTA_USERS + "/" + JOE.asString() + "/" + COUNT)
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
+
+        @Test
+        void deleteCountShouldSetQuotaToEmpty() throws Exception {
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(42));
 
-        JsonPath jsonPath =
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + COUNT)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .jsonPath();
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
-        assertThat(jsonPath.getObject("user." + COUNT, Long.class)).isNull();
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).isEmpty();
+        }
     }
 
-    @Test
-    void getQuotaShouldReturnBothWhenNoSize() {
-        int maxMessage = 42;
-        maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
+    @Nested
+    class DeleteSize {
+        @Test
+        void deleteSizeShouldReturnNotFoundWhenUserDoesntExist() {
+            when()
+                .delete(QUOTA_USERS + "/" + JOE.asString() + "/" + SIZE)
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
 
+        @Test
+        void deleteSizeShouldSetQuotaToEmpty() throws Exception {
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
 
-        JsonPath jsonPath =
             given()
-                .get(QUOTA_USERS + "/" + BOB.asString())
+                .delete(QUOTA_USERS + "/" + BOB.asString() + "/" + SIZE)
             .then()
-                .statusCode(HttpStatus.OK_200)
-                .contentType(ContentType.JSON)
-                .extract()
-                .jsonPath();
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
-        assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB))).isEmpty();
+        }
     }
 
-    @Test
-    void putQuotaShouldReturnNotFoundWhenUserDoesntExist() {
-        when()
-            .put(QUOTA_USERS + "/" + JOE.asString())
-        .then()
-            .statusCode(HttpStatus.NOT_FOUND_404);
-    }
+    @Nested
+    class GetQuota {
+        @Test
+        void getQuotaShouldReturnNotFoundWhenUserDoesntExist() {
+            when()
+                .get(QUOTA_USERS + "/" + JOE.asString())
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
+
+        @Test
+        public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
+            maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(22));
+            maxQuotaManager.setDomainMaxStorage(Domain.of(PERDU_COM), QuotaSize.size(34));
+            maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(23));
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(42));
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(52));
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(42);
+            softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(52);
+            softly.assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(42);
+            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(52);
+            softly.assertThat(jsonPath.getLong("domain." + SIZE)).isEqualTo(34);
+            softly.assertThat(jsonPath.getLong("domain." + COUNT)).isEqualTo(23);
+            softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
+            softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(22);
+        }
+
+        @Test
+        public void getQuotaShouldReturnOccupation() throws Exception {
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(80));
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(100));
+            currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("occupation.count")).isEqualTo(20);
+            softly.assertThat(jsonPath.getLong("occupation.size")).isEqualTo(40);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0.2);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0.5);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0.5);
+        }
+
+        @Test
+        public void getQuotaShouldReturnOccupationWhenUnlimited() throws Exception {
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.unlimited());
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.unlimited());
+            currentQuotaManager.increase(userQuotaRootResolver.forUser(BOB), 20, 40);
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("occupation.count")).isEqualTo(20);
+            softly.assertThat(jsonPath.getLong("occupation.size")).isEqualTo(40);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.count")).isEqualTo(0);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.size")).isEqualTo(0);
+            softly.assertThat(jsonPath.getDouble("occupation.ratio.max")).isEqualTo(0);
+        }
+
+        @Test
+        public void getQuotaShouldReturnOnlySpecifiedValues() throws Exception {
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(18));
+            maxQuotaManager.setDomainMaxMessage(Domain.of(PERDU_COM), QuotaCount.count(52));
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(1111);
+            softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(52);
+            softly.assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(52);
+            softly.assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
+            softly.assertThat(jsonPath.getObject("domain." + SIZE, Long.class)).isNull();
+            softly.assertThat(jsonPath.getObject("domain." + COUNT, Long.class)).isEqualTo(18);
+            softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
+            softly.assertThat(jsonPath.getObject("global." + COUNT, Long.class)).isNull();
+        }
+
+        @Test
+        public void getQuotaShouldReturnGlobalValuesWhenNoUserValuesDefined() throws Exception {
+            maxQuotaManager.setGlobalMaxStorage(QuotaSize.size(1111));
+            maxQuotaManager.setGlobalMaxMessage(QuotaCount.count(12));
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            SoftAssertions softly = new SoftAssertions();
+            softly.assertThat(jsonPath.getLong("computed." + SIZE)).isEqualTo(1111);
+            softly.assertThat(jsonPath.getLong("computed." + COUNT)).isEqualTo(12);
+            softly.assertThat(jsonPath.getObject("user", Object.class)).isNull();
+            softly.assertThat(jsonPath.getObject("domain", Object.class)).isNull();
+            softly.assertThat(jsonPath.getLong("global." + SIZE)).isEqualTo(1111);
+            softly.assertThat(jsonPath.getLong("global." + COUNT)).isEqualTo(12);
+        }
+
+        @Test
+        void getQuotaShouldReturnBothWhenValueSpecifiedAndEscaped() throws MailboxException {
+            int maxStorage = 42;
+            int maxMessage = 52;
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
+            assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+        }
+
+        @Test
+        void getQuotaShouldReturnBothEmptyWhenDefaultValues() {
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            assertThat(jsonPath.getObject(SIZE, Long.class)).isNull();
+            assertThat(jsonPath.getObject(COUNT, Long.class)).isNull();
+        }
+
+        @Test
+        void getQuotaShouldReturnSizeWhenNoCount() throws MailboxException {
+            int maxStorage = 42;
+            maxQuotaManager.setMaxStorage(userQuotaRootResolver.forUser(BOB), QuotaSize.size(maxStorage));
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            assertThat(jsonPath.getLong("user." + SIZE)).isEqualTo(maxStorage);
+            assertThat(jsonPath.getObject("user." + COUNT, Long.class)).isNull();
+        }
+
+        @Test
+        void getQuotaShouldReturnBothWhenNoSize() throws MailboxException {
+            int maxMessage = 42;
+            maxQuotaManager.setMaxMessage(userQuotaRootResolver.forUser(BOB), QuotaCount.count(maxMessage));
+
+
+            JsonPath jsonPath =
+                given()
+                    .get(QUOTA_USERS + "/" + BOB.asString())
+                .then()
+                    .statusCode(HttpStatus.OK_200)
+                    .contentType(ContentType.JSON)
+                    .extract()
+                    .jsonPath();
+
+            assertThat(jsonPath.getObject("user." + SIZE, Long.class)).isNull();
+            assertThat(jsonPath.getLong("user." + COUNT)).isEqualTo(maxMessage);
+        }
+    }
+
+    @Nested
+    class PutQuota {
+
+        @Test
+        void putQuotaShouldReturnNotFoundWhenUserDoesntExist() {
+            when()
+                .put(QUOTA_USERS + "/" + JOE.asString())
+            .then()
+                .statusCode(HttpStatus.NOT_FOUND_404);
+        }
 
-    @Test
-    void putQuotaShouldUpdateBothQuota() throws Exception {
-        given()
-            .body("{\"count\":52,\"size\":42}")
-            .put(QUOTA_USERS + "/" + BOB.asString())
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
-            .contains(QuotaCount.count(52));
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
-            .contains(QuotaSize.size(42));
-    }
+        @Test
+        void putQuotaShouldUpdateBothQuota() throws Exception {
+            given()
+                .body("{\"count\":52,\"size\":42}")
+                .put(QUOTA_USERS + "/" + BOB.asString())
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-    @Test
-    void putQuotaShouldUpdateBothQuotaWhenEscaped() throws Exception {
-        given()
-            .body("{\"count\":52,\"size\":42}")
-            .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
-
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
-            .contains(QuotaCount.count(52));
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
-            .contains(QuotaSize.size(42));
-    }
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaCount.count(52));
+            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaSize.size(42));
+        }
 
-    @Test
-    void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
-        given()
-            .body("{\"count\":null,\"count\":null}")
-            .put(QUOTA_USERS + "/" + BOB.asString())
-        .then()
-            .statusCode(HttpStatus.NO_CONTENT_204);
+        @Test
+        void putQuotaShouldUpdateBothQuotaWhenEscaped() throws Exception {
+            given()
+                .body("{\"count\":52,\"size\":42}")
+                .put(QUOTA_USERS + "/" + ESCAPED_BOB.asString())
+            .then()
+                .statusCode(HttpStatus.NO_CONTENT_204);
 
-        assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB))).isEmpty();
-        assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB))).isEmpty();
+            assertThat(maxQuotaManager.getMaxMessage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaCount.count(52));
+            assertThat(maxQuotaManager.getMaxStorage(userQuotaRootResolver.forUser(BOB)))
+                .contains(QuotaSize.size(42));
+        }
     }
 
 }


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