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 ro...@apache.org on 2018/02/27 13:27:44 UTC
[4/5] james-project git commit: JAMES-2344 First implementation of
admin API for User Quota
JAMES-2344 First implementation of admin API for User Quota
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo
Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/e87c0553
Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/e87c0553
Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/e87c0553
Branch: refs/heads/master
Commit: e87c05530de5d53d1d38d83fce86717cd2ef6f79
Parents: 159886f
Author: Matthieu Baechler <ma...@apache.org>
Authored: Tue Feb 20 18:39:52 2018 +0100
Committer: Matthieu Baechler <ma...@apache.org>
Committed: Tue Feb 27 09:59:23 2018 +0100
----------------------------------------------------------------------
.../apache/james/mailbox/model/QuotaRoot.java | 6 +
.../protocols/webadmin/webadmin-mailbox/pom.xml | 6 +
.../james/webadmin/routes/UserQuotaRoutes.java | 281 ++++++++++++
.../webadmin/service/UserQuotaService.java | 77 ++++
.../webadmin/routes/UserQuotaRoutesTest.java | 457 +++++++++++++++++++
5 files changed, 827 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/james-project/blob/e87c0553/mailbox/api/src/main/java/org/apache/james/mailbox/model/QuotaRoot.java
----------------------------------------------------------------------
diff --git a/mailbox/api/src/main/java/org/apache/james/mailbox/model/QuotaRoot.java b/mailbox/api/src/main/java/org/apache/james/mailbox/model/QuotaRoot.java
index 885540b..debb37a 100644
--- a/mailbox/api/src/main/java/org/apache/james/mailbox/model/QuotaRoot.java
+++ b/mailbox/api/src/main/java/org/apache/james/mailbox/model/QuotaRoot.java
@@ -26,6 +26,12 @@ import com.google.common.base.Objects;
*/
public class QuotaRoot {
+ private static final String USER = "user-";
+
+ public static QuotaRoot forUser(String value) {
+ return new QuotaRoot(USER + value);
+ }
+
public static QuotaRoot quotaRoot(String value) {
return new QuotaRoot(value);
}
http://git-wip-us.apache.org/repos/asf/james-project/blob/e87c0553/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 dfe3820..bfed1ee 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -35,6 +35,12 @@
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
+ <artifactId>james-server-dnsservice-api</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
<artifactId>apache-james-mailbox-api</artifactId>
</dependency>
<dependency>
http://git-wip-us.apache.org/repos/asf/james-project/blob/e87c0553/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
new file mode 100644
index 0000000..b72d65f
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/UserQuotaRoutes.java
@@ -0,0 +1,281 @@
+/****************************************************************
+ * 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 javax.inject.Inject;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import org.apache.james.user.api.UsersRepository;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.QuotaRequest;
+import org.apache.james.webadmin.service.UserQuotaService;
+import org.apache.james.webadmin.utils.ErrorResponder;
+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.eclipse.jetty.http.HttpStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import spark.Request;
+import spark.Service;
+
+@Api(tags = "UserQuota")
+@Path(UserQuotaRoutes.QUOTA_ENDPOINT)
+@Produces("application/json")
+public class UserQuotaRoutes implements Routes {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(Routes.class);
+
+ private static final String USER = "user";
+ static final String QUOTA_ENDPOINT = "/quota/users/:" + USER;
+ private static final String COUNT_ENDPOINT = QUOTA_ENDPOINT + "/count";
+ private static final String SIZE_ENDPOINT = QUOTA_ENDPOINT + "/size";
+
+ private final UsersRepository usersRepository;
+ private final UserQuotaService userQuotaService;
+ private final JsonTransformer jsonTransformer;
+ private final JsonExtractor<QuotaDTO> jsonExtractor;
+ private Service service;
+
+ @Inject
+ public UserQuotaRoutes(UsersRepository usersRepository, UserQuotaService userQuotaService, JsonTransformer jsonTransformer) {
+ this.usersRepository = usersRepository;
+ this.userQuotaService = userQuotaService;
+ this.jsonTransformer = jsonTransformer;
+ this.jsonExtractor = new JsonExtractor<>(QuotaDTO.class);
+ }
+
+ @Override
+ public void define(Service service) {
+ this.service = service;
+
+ defineGetQuotaCount();
+ defineDeleteQuotaCount();
+ defineUpdateQuotaCount();
+
+ defineGetQuotaSize();
+ defineDeleteQuotaSize();
+ defineUpdateQuotaSize();
+
+ defineGetQuota();
+ defineUpdateQuota();
+ }
+
+ @PUT
+ @ApiOperation(value = "Updating count and size at the same time")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "org.apache.james.webadmin.dto.QuotaDTO", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer or not unlimited value (-1)."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuota() {
+ service.put(QUOTA_ENDPOINT, ((request, response) -> {
+ String user = checkUserExist(request);
+ QuotaDTO quotaDTO = parseQuotaDTO(request);
+ userQuotaService.defineQuota(user, quotaDTO);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ }));
+ }
+
+ @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"
+ )
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = QuotaDTO.class),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuota() {
+ service.get(QUOTA_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ return userQuotaService.getQuota(user);
+ }, jsonTransformer);
+ }
+
+ @DELETE
+ @Path("/size")
+ @ApiOperation(value = "Removing per user mail size limitation by updating to unlimited value")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The value is updated to unlimited value."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineDeleteQuotaSize() {
+ service.delete(SIZE_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ userQuotaService.deleteMaxSizeQuota(user);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @PUT
+ @Path("/size")
+ @ApiOperation(value = "Updating per user mail size limitation")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "integer", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuotaSize() {
+ service.put(SIZE_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ QuotaRequest quotaRequest = parseQuotaRequest(request);
+ userQuotaService.defineMaxSizeQuota(user, quotaRequest);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @GET
+ @Path("/size")
+ @ApiOperation(value = "Reading per user mail size limitation")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = Long.class),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuotaSize() {
+ service.get(SIZE_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ return userQuotaService.getMaxSizeQuota(user);
+ }, jsonTransformer);
+ }
+
+ @DELETE
+ @Path("/count")
+ @ApiOperation(value = "Removing per user mail count limitation by updating to unlimited value")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "The value is updated to unlimited value."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineDeleteQuotaCount() {
+ service.delete(COUNT_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ userQuotaService.deleteMaxCountQuota(user);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @PUT
+ @Path("/count")
+ @ApiOperation(value = "Updating per user mail count limitation")
+ @ApiImplicitParams({
+ @ApiImplicitParam(required = true, dataType = "integer", paramType = "body")
+ })
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.NO_CONTENT_204, message = "OK. The value has been updated."),
+ @ApiResponse(code = HttpStatus.BAD_REQUEST_400, message = "The body is not a positive integer."),
+ @ApiResponse(code = HttpStatus.CONFLICT_409, message = "The requested restriction can't be enforced right now."),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineUpdateQuotaCount() {
+ service.put(COUNT_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ QuotaRequest quotaRequest = parseQuotaRequest(request);
+ userQuotaService.defineMaxCountQuota(user, quotaRequest);
+ response.status(HttpStatus.NO_CONTENT_204);
+ return response;
+ });
+ }
+
+ @GET
+ @Path("/count")
+ @ApiOperation(value = "Reading per user mail count limitation")
+ @ApiResponses(value = {
+ @ApiResponse(code = HttpStatus.OK_200, message = "OK", response = Long.class),
+ @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.")
+ })
+ public void defineGetQuotaCount() {
+ service.get(COUNT_ENDPOINT, (request, response) -> {
+ String user = checkUserExist(request);
+ return userQuotaService.getMaxCountQuota(user);
+ }, jsonTransformer);
+ }
+
+ private String checkUserExist(Request request) throws UsersRepositoryException {
+ String user = request.params(USER);
+ if (!usersRepository.contains(user)) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.NOT_FOUND_404)
+ .type(ErrorType.NOT_FOUND)
+ .message("User not found")
+ .haltError();
+ }
+ return user;
+ }
+
+ private QuotaDTO parseQuotaDTO(Request request) {
+ try {
+ return jsonExtractor.parse(request.body());
+ } catch (IllegalArgumentException e) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .type(ErrorType.INVALID_ARGUMENT)
+ .message("Quota should be positive or unlimited (-1)")
+ .cause(e)
+ .haltError();
+ } catch (JsonExtractException e) {
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .type(ErrorType.INVALID_ARGUMENT)
+ .message("Malformed JSON input")
+ .cause(e)
+ .haltError();
+ }
+ }
+
+ private QuotaRequest parseQuotaRequest(Request request) {
+ try {
+ return QuotaRequest.parse(request.body());
+ } catch (IllegalArgumentException e) {
+ LOGGER.info("Invalid quota. Need to be an integer value greater than 0");
+ throw ErrorResponder.builder()
+ .statusCode(HttpStatus.BAD_REQUEST_400)
+ .type(ErrorType.INVALID_ARGUMENT)
+ .message("Invalid quota. Need to be an integer value greater than 0")
+ .cause(e)
+ .haltError();
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/e87c0553/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
new file mode 100644
index 0000000..ddaf630
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/UserQuotaService.java
@@ -0,0 +1,77 @@
+/****************************************************************
+ * 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.service;
+
+import javax.inject.Inject;
+
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.model.Quota;
+import org.apache.james.mailbox.model.QuotaRoot;
+import org.apache.james.mailbox.quota.MaxQuotaManager;
+import org.apache.james.webadmin.dto.QuotaDTO;
+import org.apache.james.webadmin.dto.QuotaRequest;
+
+public class UserQuotaService {
+
+ private final MaxQuotaManager maxQuotaManager;
+
+ @Inject
+ public UserQuotaService(MaxQuotaManager maxQuotaManager) {
+ this.maxQuotaManager = maxQuotaManager;
+ }
+
+ public void defineQuota(String user, QuotaDTO quota) throws MailboxException {
+ QuotaRoot quotaRoot = QuotaRoot.forUser(user);
+ maxQuotaManager.setMaxMessage(quotaRoot, quota.getCount());
+ maxQuotaManager.setMaxStorage(quotaRoot, quota.getSize());
+ }
+
+ public QuotaDTO getQuota(String user) throws MailboxException {
+ QuotaRoot quotaRoot = QuotaRoot.forUser(user);
+ return QuotaDTO
+ .builder()
+ .count(maxQuotaManager.getMaxMessage(quotaRoot))
+ .size(maxQuotaManager.getMaxStorage(quotaRoot))
+ .build();
+ }
+
+ public Long getMaxSizeQuota(String user) throws MailboxException {
+ return maxQuotaManager.getMaxStorage(QuotaRoot.forUser(user));
+ }
+
+ public void defineMaxSizeQuota(String user, QuotaRequest quotaRequest) throws MailboxException {
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(user), quotaRequest.getValue());
+ }
+
+ public void deleteMaxSizeQuota(String user) throws MailboxException {
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(user), Quota.UNLIMITED);
+ }
+
+ public Long getMaxCountQuota(String user) throws MailboxException {
+ return maxQuotaManager.getMaxMessage(QuotaRoot.forUser(user));
+ }
+
+ public void defineMaxCountQuota(String user, QuotaRequest quotaRequest) throws MailboxException {
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(user), quotaRequest.getValue());
+ }
+
+ public void deleteMaxCountQuota(String user) throws MailboxException {
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(user), Quota.UNLIMITED);
+ }
+}
http://git-wip-us.apache.org/repos/asf/james-project/blob/e87c0553/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
new file mode 100644
index 0000000..86a09af
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/UserQuotaRoutesTest.java
@@ -0,0 +1,457 @@
+/****************************************************************
+ * 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 com.jayway.restassured.RestAssured.given;
+import static com.jayway.restassured.RestAssured.when;
+import static org.apache.james.mailbox.model.Quota.UNLIMITED;
+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.dnsservice.api.InMemoryDNSService;
+import org.apache.james.domainlist.memory.MemoryDomainList;
+import org.apache.james.mailbox.inmemory.quota.InMemoryPerUserMaxQuotaManager;
+import org.apache.james.mailbox.model.QuotaRoot;
+import org.apache.james.metrics.api.NoopMetricFactory;
+import org.apache.james.user.api.UsersRepositoryException;
+import org.apache.james.user.memory.MemoryUsersRepository;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.service.UserQuotaService;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.jayway.restassured.RestAssured;
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.path.json.JsonPath;
+
+public class UserQuotaRoutesTest {
+
+ private static final String QUOTA_USERS = "/quota/users";
+ private static final String PERDU_COM = "perdu.com";
+ private static final String BOB = "bob@" + PERDU_COM;
+ private static final String JOE = "joe@" + PERDU_COM;
+ 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 MemoryUsersRepository usersRepository;
+
+ @Before
+ public void setUp() throws Exception {
+ maxQuotaManager = new InMemoryPerUserMaxQuotaManager();
+ MemoryDomainList memoryDomainList = new MemoryDomainList(new InMemoryDNSService());
+ memoryDomainList.setAutoDetect(false);
+ memoryDomainList.addDomain(PERDU_COM);
+ usersRepository = MemoryUsersRepository.withVirtualHosting();
+ usersRepository.setDomainList(memoryDomainList);
+ usersRepository.addUser(BOB, PASSWORD);
+ UserQuotaService userQuotaService = new UserQuotaService(maxQuotaManager);
+ UserQuotaRoutes userQuotaRoutes = new UserQuotaRoutes(usersRepository, userQuotaService, new JsonTransformer());
+ webAdminServer = WebAdminUtils.createWebAdminServer(
+ new NoopMetricFactory(),
+ userQuotaRoutes);
+ webAdminServer.configure(NO_CONFIGURATION);
+ webAdminServer.await();
+
+ RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer)
+ .build();
+ RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+ }
+
+ @After
+ public void stop() {
+ webAdminServer.destroy();
+ }
+
+ @Test
+ public void getCountShouldReturnNotFoundWhenUserDoesntExist() {
+ when()
+ .get(QUOTA_USERS + "/" + JOE + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getCountShouldReturnUnlimitedByDefault() throws UsersRepositoryException {
+ long quota =
+ given()
+ .get(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(quota).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getCountShouldReturnStoredValue() throws Exception {
+ int value = 42;
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), value);
+
+ Long actual =
+ given()
+ .get(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(actual).isEqualTo(value);
+ }
+
+ @Test
+ public void putCountShouldReturnNotFoundWhenUserDoesntExist() {
+ given()
+ .body("invalid")
+ .when()
+ .put(QUOTA_USERS + "/" + JOE + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+
+ @Test
+ public void putCountShouldRejectInvalid() throws Exception {
+ Map<String, Object> errors = given()
+ .body("invalid")
+ .put(QUOTA_USERS + "/" + BOB + "/" + 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 than 0")
+ .containsEntry("cause", "For input string: \"invalid\"");
+ }
+
+ @Test
+ public void putCountShouldRejectNegative() throws Exception {
+ Map<String, Object> errors = given()
+ .body("-1")
+ .put(QUOTA_USERS + "/" + BOB + "/" + 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 than 0");
+ }
+
+ @Test
+ public void putCountShouldAcceptValidValue() throws Exception {
+ given()
+ .body("42")
+ .put(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+ }
+
+
+ @Test
+ @Ignore("no link between quota and mailbox for now")
+ public void putCountShouldRejectTooSmallValue() throws Exception {
+ given()
+ .body("42")
+ .put(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+ }
+
+ @Test
+ public void deleteCountShouldReturnNotFoundWhenUserDoesntExist() {
+ when()
+ .delete(QUOTA_USERS + "/" + JOE + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+
+ @Test
+ public void deleteCountShouldSetQuotaToUnlimited() throws Exception {
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), 42);
+
+ given()
+ .delete(QUOTA_USERS + "/" + BOB + "/" + COUNT)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getSizeShouldReturnNotFoundWhenUserDoesntExist() {
+ when()
+ .get(QUOTA_USERS + "/" + JOE + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getSizeShouldReturnUnlimitedByDefault() throws UsersRepositoryException {
+ long quota =
+ given()
+ .get(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(quota).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getSizeShouldReturnStoredValue() throws Exception {
+ long value = 42;
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), value);
+
+
+ long quota =
+ given()
+ .get(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .as(Long.class);
+
+ assertThat(quota).isEqualTo(value);
+ }
+
+ @Test
+ public void putSizeShouldRejectInvalid() throws Exception {
+ Map<String, Object> errors = given()
+ .body("invalid")
+ .put(QUOTA_USERS + "/" + BOB + "/" + 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 than 0")
+ .containsEntry("cause", "For input string: \"invalid\"");
+ }
+
+ @Test
+ public void putSizeShouldReturnNotFoundWhenUserDoesntExist() throws Exception {
+ given()
+ .body("123")
+ .when()
+ .put(QUOTA_USERS + "/" + JOE + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void putSizeShouldRejectNegative() throws Exception {
+ Map<String, Object> errors = given()
+ .body("-1")
+ .put(QUOTA_USERS + "/" + BOB + "/" + 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 than 0");
+ }
+
+ @Test
+ public void putSizeShouldAcceptValidValue() throws Exception {
+ given()
+ .body("42")
+ .put(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+ }
+
+ @Test
+ public void deleteSizeShouldReturnNotFoundWhenUserDoesntExist() throws Exception {
+ when()
+ .delete(QUOTA_USERS + "/" + JOE + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void deleteSizeShouldSetQuotaToUnlimited() throws Exception {
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), 42);
+
+ given()
+ .delete(QUOTA_USERS + "/" + BOB + "/" + SIZE)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getQuotaShouldReturnNotFoundWhenUserDoesntExist() throws Exception {
+ when()
+ .get(QUOTA_USERS + "/" + JOE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothWhenValueSpecified() throws Exception {
+ int maxStorage = 42;
+ int maxMessage = 52;
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), maxStorage);
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), maxMessage);
+
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getLong(SIZE)).isEqualTo(maxStorage);
+ assertThat(jsonPath.getLong(COUNT)).isEqualTo(maxMessage);
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothDefaultValues() throws Exception {
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getLong(SIZE)).isEqualTo(UNLIMITED);
+ assertThat(jsonPath.getLong(COUNT)).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothWhenNoCount() throws Exception {
+ int maxStorage = 42;
+ maxQuotaManager.setMaxStorage(QuotaRoot.forUser(BOB), maxStorage);
+
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getLong(SIZE)).isEqualTo(maxStorage);
+ assertThat(jsonPath.getLong(COUNT)).isEqualTo(UNLIMITED);
+ }
+
+ @Test
+ public void getQuotaShouldReturnBothWhenNoSize() throws Exception {
+ int maxMessage = 42;
+ maxQuotaManager.setMaxMessage(QuotaRoot.forUser(BOB), maxMessage);
+
+
+ JsonPath jsonPath =
+ given()
+ .get(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.OK_200)
+ .contentType(ContentType.JSON)
+ .extract()
+ .jsonPath();
+
+ assertThat(jsonPath.getLong(SIZE)).isEqualTo(UNLIMITED);
+ assertThat(jsonPath.getLong(COUNT)).isEqualTo(maxMessage);
+ }
+
+ @Test
+ public void putQuotaShouldReturnNotFoundWhenUserDoesntExist() throws Exception {
+ when()
+ .put(QUOTA_USERS + "/" + JOE)
+ .then()
+ .statusCode(HttpStatus.NOT_FOUND_404);
+ }
+
+ @Test
+ public void putQuotaShouldUpdateBothQuota() throws Exception {
+ given()
+ .body("{\"" + COUNT + "\":52,\"" + SIZE + "\":42}")
+ .put(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(52);
+ assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(42);
+ }
+
+ @Test
+ public void putQuotaShouldBeAbleToRemoveBothQuota() throws Exception {
+ given()
+ .body("{\"" + COUNT + "\":-1,\"" + SIZE + "\":-1}")
+ .put(QUOTA_USERS + "/" + BOB)
+ .then()
+ .statusCode(HttpStatus.NO_CONTENT_204);
+
+ assertThat(maxQuotaManager.getMaxMessage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+ assertThat(maxQuotaManager.getMaxStorage(QuotaRoot.forUser(BOB))).isEqualTo(UNLIMITED);
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org