Repository: james-project Updated Branches: refs/heads/master 5a4c0ded9 -> b10fa18aa
JAMES-2151 Administer Sieve quotas via webadmin >From the awesome work of Sebastian Górecki on >https://github.com/linagora/james-project/pull/1066 Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/b9ac736b Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/b9ac736b Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/b9ac736b Branch: refs/heads/master Commit: b9ac736b4644c4471e931c12dffcd167e32aa3ba Parents: 5a4c0de Author: Sebastian Górecki <[email protected]> Authored: Tue Oct 24 23:10:02 2017 +0200 Committer: benwa <[email protected]> Committed: Tue Jun 26 16:05:27 2018 +0700 ---------------------------------------------------------------------- .../api/SieveQuotaRepository.java | 46 ++++ .../sieverepository/api/SieveRepository.java | 19 +- .../james/webadmin/routes/SieveQuotaRoutes.java | 260 +++++++++++++++++++ .../routes/InMemorySieveQuotaRepository.java | 82 ++++++ .../webadmin/routes/SieveQuotaRoutesTest.java | 215 +++++++++++++++ 5 files changed, 604 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/b9ac736b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveQuotaRepository.java ---------------------------------------------------------------------- diff --git a/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveQuotaRepository.java b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveQuotaRepository.java new file mode 100644 index 0000000..ec11c1e --- /dev/null +++ b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveQuotaRepository.java @@ -0,0 +1,46 @@ +/* + * 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.sieverepository.api; + +import org.apache.james.sieverepository.api.exception.QuotaNotFoundException; +import org.apache.james.sieverepository.api.exception.StorageException; + +/** + * SieveQuotaRepository + */ +public interface SieveQuotaRepository { + + boolean hasQuota() throws StorageException; + + long getQuota() throws QuotaNotFoundException, StorageException; + + void setQuota(long quota) throws StorageException; + + void removeQuota() throws QuotaNotFoundException, StorageException; + + boolean hasQuota(String user) throws StorageException; + + long getQuota(String user) throws QuotaNotFoundException, StorageException; + + void setQuota(String user, long quota) throws StorageException; + + void removeQuota(String user) throws QuotaNotFoundException, StorageException; +} http://git-wip-us.apache.org/repos/asf/james-project/blob/b9ac736b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveRepository.java ---------------------------------------------------------------------- diff --git a/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveRepository.java b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveRepository.java index 9bdb55e..f93d080 100644 --- a/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveRepository.java +++ b/server/data/data-api/src/main/java/org/apache/james/sieverepository/api/SieveRepository.java @@ -26,7 +26,6 @@ import java.util.List; import org.apache.james.sieverepository.api.exception.DuplicateException; import org.apache.james.sieverepository.api.exception.IsActiveException; import org.apache.james.sieverepository.api.exception.QuotaExceededException; -import org.apache.james.sieverepository.api.exception.QuotaNotFoundException; import org.apache.james.sieverepository.api.exception.ScriptNotFoundException; import org.apache.james.sieverepository.api.exception.StorageException; import org.joda.time.DateTime; @@ -35,7 +34,7 @@ import org.joda.time.DateTime; /** * <code>SieveRepository</code> */ -public interface SieveRepository { +public interface SieveRepository extends SieveQuotaRepository { String NO_SCRIPT_NAME = ""; @@ -68,20 +67,4 @@ public interface SieveRepository { void renameScript(String user, String oldName, String newName) throws ScriptNotFoundException, DuplicateException, StorageException; - boolean hasQuota() throws StorageException; - - long getQuota() throws QuotaNotFoundException, StorageException; - - void setQuota(long quota) throws StorageException; - - void removeQuota() throws QuotaNotFoundException, StorageException; - - boolean hasQuota(String user) throws StorageException; - - long getQuota(String user) throws QuotaNotFoundException, StorageException; - - void setQuota(String user, long quota) throws StorageException; - - void removeQuota(String user) throws QuotaNotFoundException, StorageException; - } http://git-wip-us.apache.org/repos/asf/james-project/blob/b9ac736b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/SieveQuotaRoutes.java ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/SieveQuotaRoutes.java b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/SieveQuotaRoutes.java new file mode 100644 index 0000000..1c779db --- /dev/null +++ b/server/protocols/webadmin/webadmin-data/src/main/java/org/apache/james/webadmin/routes/SieveQuotaRoutes.java @@ -0,0 +1,260 @@ +/**************************************************************** + * 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.Constants.SEPARATOR; + +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.sieverepository.api.SieveQuotaRepository; +import org.apache.james.sieverepository.api.exception.QuotaNotFoundException; +import org.apache.james.webadmin.Constants; +import org.apache.james.webadmin.Routes; +import org.apache.james.webadmin.utils.ErrorResponder; +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 = "SieveQuota") +@Path(SieveQuotaRoutes.ROOT_PATH) +@Produces("application/json") +public class SieveQuotaRoutes implements Routes { + + static final String ROOT_PATH = "/sieve/quota"; + private static final String USER_ID = "userId"; + private static final String USER_SIEVE_QUOTA_PATH = ROOT_PATH + SEPARATOR + ":" + USER_ID; + private static final String REQUESTED_SIZE = "requestedSize"; + private static final Logger LOGGER = LoggerFactory.getLogger(SieveQuotaRoutes.class); + + private final SieveQuotaRepository sieveQuotaRepository; + private final JsonTransformer jsonTransformer; + private final JsonExtractor<Long> jsonExtractor; + + @Inject + public SieveQuotaRoutes(SieveQuotaRepository sieveQuotaRepository, JsonTransformer jsonTransformer) { + this.sieveQuotaRepository = sieveQuotaRepository; + this.jsonTransformer = jsonTransformer; + this.jsonExtractor = new JsonExtractor<>(Long.class); + } + + @Override + public void define(Service service) { + defineGetGlobalSieveQuota(service); + defineUpdateGlobalSieveQuota(service); + defineRemoveGlobalSieveQuota(service); + + defineGetPerUserSieveQuota(service); + defineUpdatePerUserSieveQuota(service); + defineRemovePerUserSieveQuota(service); + } + + @GET + @ApiOperation(value = "Reading global sieve quota size") + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", response = Long.class), + @ApiResponse(code = 404, message = "Global sieve quota not set."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineGetGlobalSieveQuota(Service service) { + service.get(ROOT_PATH, (request, response) -> { + try { + long sieveQuota = sieveQuotaRepository.getQuota(); + response.status(HttpStatus.OK_200); + return sieveQuota; + } catch (QuotaNotFoundException e) { + LOGGER.info("Global sieve quota not set", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.NOT_FOUND) + .statusCode(HttpStatus.NOT_FOUND_404) + .message("Global sieve quota not set") + .haltError(); + } + }, jsonTransformer); + } + + @PUT + @ApiOperation(value = "Update global sieve quota size") + @ApiImplicitParams({ + @ApiImplicitParam(required = true, dataType = "long", name = REQUESTED_SIZE, paramType = "body") + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", response = Long.class), + @ApiResponse(code = 400, message = "The body is not a positive integer."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineUpdateGlobalSieveQuota(Service service) { + service.put(ROOT_PATH, (request, response) -> { + try { + Long requestedSize = extractRequestedQuotaSizeFromRequest(request); + sieveQuotaRepository.setQuota(requestedSize); + response.status(HttpStatus.NO_CONTENT_204); + return Constants.EMPTY_BODY; + } catch (JsonExtractException e) { + LOGGER.info("Malformed JSON", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.INVALID_ARGUMENT) + .statusCode(HttpStatus.BAD_REQUEST_400) + .message("Malformed JSON") + .cause(e) + .haltError(); + } + }, jsonTransformer); + } + + @DELETE + @ApiOperation(value = "Removes global sieve quota") + @ApiResponses(value = { + @ApiResponse(code = 204, message = "Global sieve quota removed."), + @ApiResponse(code = 404, message = "Global sieve quota not set."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineRemoveGlobalSieveQuota(Service service) { + service.delete(ROOT_PATH, (request, response) -> { + try { + sieveQuotaRepository.removeQuota(); + response.status(HttpStatus.NO_CONTENT_204); + } catch (QuotaNotFoundException e) { + LOGGER.info("Global sieve quota not set", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.NOT_FOUND) + .statusCode(HttpStatus.NOT_FOUND_404) + .message("Global sieve quota not set") + .haltError(); + } + return Constants.EMPTY_BODY; + }); + } + + @GET + @Path(value = ROOT_PATH + "/{" + USER_ID + "}") + @ApiImplicitParams({ + @ApiImplicitParam(required = true, dataType = "string", name = USER_ID, paramType = "path") + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", response = Long.class), + @ApiResponse(code = 404, message = "User sieve quota not set."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineGetPerUserSieveQuota(Service service) { + service.get(USER_SIEVE_QUOTA_PATH, (request, response) -> { + String userId = request.params(USER_ID); + try { + long userQuota = sieveQuotaRepository.getQuota(userId); + response.status(HttpStatus.OK_200); + return userQuota; + } catch (QuotaNotFoundException e) { + LOGGER.info("User sieve quota not set", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.NOT_FOUND) + .statusCode(HttpStatus.NOT_FOUND_404) + .message("User sieve quota not set") + .haltError(); + } + }, jsonTransformer); + } + + @PUT + @Path(value = ROOT_PATH + "/{" + USER_ID + "}") + @ApiImplicitParams({ + @ApiImplicitParam(required = true, dataType = "string", name = USER_ID, paramType = "path"), + @ApiImplicitParam(required = true, dataType = "long", name = REQUESTED_SIZE, paramType = "body") + }) + @ApiResponses(value = { + @ApiResponse(code = 200, message = "OK", response = Long.class), + @ApiResponse(code = 400, message = "The body is not a positive integer."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineUpdatePerUserSieveQuota(Service service) { + service.put(USER_SIEVE_QUOTA_PATH, (request, response) -> { + String userId = request.params(USER_ID); + try { + Long requestedSize = extractRequestedQuotaSizeFromRequest(request); + sieveQuotaRepository.setQuota(userId, requestedSize); + response.status(HttpStatus.NO_CONTENT_204); + } catch (JsonExtractException e) { + LOGGER.info("Malformed JSON", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.INVALID_ARGUMENT) + .statusCode(HttpStatus.BAD_REQUEST_400) + .message("Malformed JSON") + .cause(e) + .haltError(); + } + return Constants.EMPTY_BODY; + }, jsonTransformer); + } + + @DELETE + @Path(value = ROOT_PATH + "/{" + USER_ID + "}") + @ApiImplicitParams({ + @ApiImplicitParam(required = true, dataType = "string", name = USER_ID, paramType = "path") + }) + @ApiResponses(value = { + @ApiResponse(code = 204, message = "User sieve quota removed."), + @ApiResponse(code = 404, message = "User sieve quota not set."), + @ApiResponse(code = 500, message = "Internal server error - Something went bad on the server side.") + }) + public void defineRemovePerUserSieveQuota(Service service) { + service.delete(USER_SIEVE_QUOTA_PATH, (request, response) -> { + String userId = request.params(USER_ID); + try { + sieveQuotaRepository.removeQuota(userId); + response.status(HttpStatus.NO_CONTENT_204); + } catch (QuotaNotFoundException e) { + LOGGER.info("User sieve quota not set", e); + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.NOT_FOUND) + .statusCode(HttpStatus.NOT_FOUND_404) + .message("User sieve quota not set") + .haltError(); + } + return Constants.EMPTY_BODY; + }); + } + + private Long extractRequestedQuotaSizeFromRequest(Request request) throws JsonExtractException { + Long requestedSize = jsonExtractor.parse(request.body()); + if (requestedSize < 0) { + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.INVALID_ARGUMENT) + .statusCode(HttpStatus.BAD_REQUEST_400) + .message("Requested quota size have to be a positive integer") + .haltError(); + } + return requestedSize; + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/b9ac736b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/InMemorySieveQuotaRepository.java ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/InMemorySieveQuotaRepository.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/InMemorySieveQuotaRepository.java new file mode 100644 index 0000000..d3aedd0 --- /dev/null +++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/InMemorySieveQuotaRepository.java @@ -0,0 +1,82 @@ +/**************************************************************** + * 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 java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.james.sieverepository.api.SieveQuotaRepository; +import org.apache.james.sieverepository.api.exception.QuotaNotFoundException; + +public class InMemorySieveQuotaRepository implements SieveQuotaRepository { + + private Optional<Long> globalQuota = Optional.empty(); + + private Map<String, Long> userQuota = new ConcurrentHashMap<>(); + + @Override + public boolean hasQuota() { + return globalQuota.isPresent(); + } + + @Override + public long getQuota() throws QuotaNotFoundException { + return globalQuota.orElseThrow(QuotaNotFoundException::new); + } + + @Override + public void setQuota(long quota) { + this.globalQuota = Optional.of(quota); + } + + @Override + public void removeQuota() throws QuotaNotFoundException { + if (!globalQuota.isPresent()) { + throw new QuotaNotFoundException(); + } + globalQuota = Optional.empty(); + } + + @Override + public boolean hasQuota(String user) { + return userQuota.containsKey(user); + } + + @Override + public long getQuota(String user) throws QuotaNotFoundException { + return Optional.ofNullable(userQuota.get(user)) + .orElseThrow(QuotaNotFoundException::new); + } + + @Override + public void setQuota(String user, long quota) { + userQuota.put(user, quota); + } + + @Override + public void removeQuota(String user) throws QuotaNotFoundException { + Optional<Long> quotaValue = Optional.ofNullable(userQuota.get(user)); + if (!quotaValue.isPresent()) { + throw new QuotaNotFoundException(); + } + userQuota.remove(user); + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/b9ac736b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/SieveQuotaRoutesTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/SieveQuotaRoutesTest.java b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/SieveQuotaRoutesTest.java new file mode 100644 index 0000000..e127901 --- /dev/null +++ b/server/protocols/webadmin/webadmin-data/src/test/java/org/apache/james/webadmin/routes/SieveQuotaRoutesTest.java @@ -0,0 +1,215 @@ +/**************************************************************** + * 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 org.apache.james.webadmin.Constants.SEPARATOR; +import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION; +import static org.apache.james.webadmin.routes.SieveQuotaRoutes.ROOT_PATH; +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.james.metrics.logger.DefaultMetricFactory; +import org.apache.james.sieverepository.api.SieveQuotaRepository; +import org.apache.james.webadmin.WebAdminServer; +import org.apache.james.webadmin.WebAdminUtils; +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 com.jayway.restassured.RestAssured; +import com.jayway.restassured.http.ContentType; + +public class SieveQuotaRoutesTest { + + private static final String USER_A = "userA"; + + private WebAdminServer webAdminServer; + private SieveQuotaRepository sieveRepository; + + @BeforeEach + public void setUp() throws Exception { + sieveRepository = new InMemorySieveQuotaRepository(); + webAdminServer = WebAdminUtils.createWebAdminServer( + new DefaultMetricFactory(), + new SieveQuotaRoutes(sieveRepository, new JsonTransformer())); + webAdminServer.configure(NO_CONFIGURATION); + webAdminServer.await(); + + RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer) + .build(); + } + + @AfterEach + public void tearDown() { + webAdminServer.destroy(); + } + + @Test + public void getGlobalSieveQuotaShouldReturn404WhenNoQuotaSet() { + given() + .get(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(404); + } + + @Test + public void getGlobalSieveQuotaShouldReturnStoredValue() throws Exception { + long value = 1000L; + sieveRepository.setQuota(value); + + long actual = + given() + .get(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .extract() + .as(Long.class); + + assertThat(actual).isEqualTo(value); + } + + @Test + public void updateGlobalSieveQuotaShouldUpdateStoredValue() throws Exception { + sieveRepository.setQuota(500L); + long requiredSize = 1024L; + + given() + .body(requiredSize) + .put(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.NO_CONTENT_204); + + assertThat(sieveRepository.getQuota()).isEqualTo(requiredSize); + } + + @Test + public void updateGlobalSieveQuotaShouldReturn400WhenMalformedJSON() { + given() + .body("invalid") + .put(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void updateGlobalSieveQuotaShouldReturn400WhenRequestedSizeNotPositiveInteger() { + given() + .body(-100L) + .put(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void removeGlobalSieveQuotaShouldReturn404WhenNoQuotaSet() { + given() + .delete(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void removeGlobalSieveQuotaShouldRemoveGlobalSieveQuota() throws Exception { + sieveRepository.setQuota(1024L); + + given() + .delete(SieveQuotaRoutes.ROOT_PATH) + .then() + .statusCode(HttpStatus.NO_CONTENT_204); + } + + @Test + public void getPerUserQuotaShouldReturn404WhenNoQuotaSetForUser() { + given() + .get(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void getPerUserSieveQuotaShouldReturnedStoredValue() throws Exception { + long value = 1024L; + sieveRepository.setQuota(USER_A, value); + + long actual = + given() + .get(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .extract() + .as(Long.class); + + assertThat(actual).isEqualTo(value); + } + + @Test + public void updatePerUserSieveQuotaShouldUpdateStoredValue() throws Exception { + sieveRepository.setQuota(USER_A, 500L); + long requiredSize = 1024L; + + given() + .body(requiredSize) + .put(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.NO_CONTENT_204); + + assertThat(sieveRepository.getQuota(USER_A)).isEqualTo(requiredSize); + } + + @Test + public void updatePerUserSieveQuotaShouldReturn400WhenMalformedJSON() { + given() + .body("invalid") + .put(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void updatePerUserSieveQuotaShouldReturn400WhenRequestedSizeNotPositiveInteger() { + given() + .body(-100L) + .put(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void removePerUserSieveQuotaShouldReturn404WhenNoQuotaSetForUser() { + given() + .delete(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void removePerUserSieveQuotaShouldRemoveQuotaForUser() throws Exception { + sieveRepository.setQuota(USER_A, 1024L); + + given() + .delete(ROOT_PATH + SEPARATOR + USER_A) + .then() + .statusCode(HttpStatus.NO_CONTENT_204); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
