Repository: james-project Updated Branches: refs/heads/master b25ee7ffe -> 6c61cdcc7
JAMES-2319 Clearing a mail queue Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/4097211f Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/4097211f Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/4097211f Branch: refs/heads/master Commit: 4097211f2e9e0737000f09186c0b9953f8c28700 Parents: b25ee7f Author: duc <trantiendu...@gmail.com> Authored: Thu May 24 11:28:18 2018 +0700 Committer: Matthieu Baechler <matth...@apache.org> Committed: Fri May 25 11:07:03 2018 +0200 ---------------------------------------------------------------------- .../webadmin/webadmin-mailqueue/pom.xml | 5 + .../james/webadmin/routes/MailQueueRoutes.java | 27 +- .../webadmin/service/ClearMailQueueTask.java | 98 ++ .../webadmin/routes/MailQueueRoutesTest.java | 1628 ++++++++++-------- src/site/markdown/server/manage-webadmin.md | 185 +- 5 files changed, 1105 insertions(+), 838 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/4097211f/server/protocols/webadmin/webadmin-mailqueue/pom.xml ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-mailqueue/pom.xml b/server/protocols/webadmin/webadmin-mailqueue/pom.xml index 6e4cfd1..cca2429 100644 --- a/server/protocols/webadmin/webadmin-mailqueue/pom.xml +++ b/server/protocols/webadmin/webadmin-mailqueue/pom.xml @@ -83,6 +83,11 @@ <scope>test</scope> </dependency> <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <scope>test</scope> + </dependency> + <dependency> <groupId>org.hamcrest</groupId> <artifactId>java-hamcrest</artifactId> <scope>test</scope> http://git-wip-us.apache.org/repos/asf/james-project/blob/4097211f/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 cff5936..ee43f56 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 @@ -45,6 +45,7 @@ import org.apache.james.webadmin.dto.ForceDelivery; import org.apache.james.webadmin.dto.MailQueueDTO; import org.apache.james.webadmin.dto.MailQueueItemDTO; import org.apache.james.webadmin.dto.TaskIdDto; +import org.apache.james.webadmin.service.ClearMailQueueTask; import org.apache.james.webadmin.service.DeleteMailsFromMailQueueTask; import org.apache.james.webadmin.utils.ErrorResponder; import org.apache.james.webadmin.utils.ErrorResponder.ErrorType; @@ -304,8 +305,8 @@ public class MailQueueRoutes implements Routes { @ApiResponse(code = HttpStatus.INTERNAL_SERVER_ERROR_500, message = "Internal server error - Something went bad on the server side.") }) public void deleteMails(Service service) { - service.delete(BASE_URL + SEPARATOR + MAIL_QUEUE_NAME + MAILS, - (request, response) -> deleteMails(request, response), + service.delete(BASE_URL + SEPARATOR + MAIL_QUEUE_NAME + MAILS, + this::deleteMails, jsonTransformer); } @@ -433,15 +434,20 @@ public class MailQueueRoutes implements Routes { } private Task deleteMailsTask(ManageableMailQueue queue, Optional<MailAddress> maybeSender, Optional<String> maybeName, Optional<MailAddress> maybeRecipient) { - if (Booleans.countTrue(maybeSender.isPresent(), maybeName.isPresent(), maybeRecipient.isPresent()) != 1) { - throw ErrorResponder.builder() - .statusCode(HttpStatus.BAD_REQUEST_400) - .type(ErrorType.INVALID_ARGUMENT) - .message("You should provide one and only one of the query parameters 'sender', 'name' or 'recipient'.") - .haltError(); + int paramCount = Booleans.countTrue(maybeSender.isPresent(), maybeName.isPresent(), maybeRecipient.isPresent()); + switch (paramCount) { + case 0: + return new ClearMailQueueTask(queue); + case 1: + return new DeleteMailsFromMailQueueTask(queue, maybeSender, maybeName, maybeRecipient); + default: + throw ErrorResponder.builder() + .statusCode(HttpStatus.BAD_REQUEST_400) + .type(ErrorType.INVALID_ARGUMENT) + .message("You should provide only one of the query parameters 'sender', 'name', 'recipient' " + + "for deleting mails by condition or no parameter for deleting all mails in the mail queue.") + .haltError(); } - - return new DeleteMailsFromMailQueueTask(queue, maybeSender, maybeName, maybeRecipient); } private void assertDelayedParamIsTrue(Request request) { @@ -453,5 +459,4 @@ public class MailQueueRoutes implements Routes { .haltError(); } } - } http://git-wip-us.apache.org/repos/asf/james-project/blob/4097211f/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/service/ClearMailQueueTask.java ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/service/ClearMailQueueTask.java b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/service/ClearMailQueueTask.java new file mode 100644 index 0000000..bbf8db9 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailqueue/src/main/java/org/apache/james/webadmin/service/ClearMailQueueTask.java @@ -0,0 +1,98 @@ +/**************************************************************** + * 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 java.util.Optional; +import java.util.function.Supplier; + +import org.apache.james.queue.api.MailQueue; +import org.apache.james.queue.api.ManageableMailQueue; +import org.apache.james.task.Task; +import org.apache.james.task.TaskExecutionDetails; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ClearMailQueueTask implements Task { + + public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation { + private final String mailQueueName; + private final long initialCount; + private final Supplier<Long> countSupplier; + + public AdditionalInformation(String mailQueueName, Supplier<Long> countSupplier) { + this.mailQueueName = mailQueueName; + this.countSupplier = countSupplier; + this.initialCount = countSupplier.get(); + } + + public String getMailQueueName() { + return mailQueueName; + } + + public long getInitialCount() { + return initialCount; + } + + public long getRemainingCount() { + return countSupplier.get(); + } + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ClearMailQueueTask.class); + public static final String TYPE = "clearMailQueue"; + + private final ManageableMailQueue queue; + private final AdditionalInformation additionalInformation; + + public ClearMailQueueTask(ManageableMailQueue queue) { + this.queue = queue; + additionalInformation = new AdditionalInformation(queue.getName(), this::getRemainingSize); + } + + @Override + public Result run() { + try { + queue.clear(); + } catch (MailQueue.MailQueueException e) { + LOGGER.error("Clear MailQueue got an exception", e); + return Result.PARTIAL; + } + + return Result.COMPLETED; + } + + @Override + public String type() { + return TYPE; + } + + @Override + public Optional<TaskExecutionDetails.AdditionalInformation> details() { + return Optional.of(additionalInformation); + } + + private long getRemainingSize() { + try { + return queue.getSize(); + } catch (MailQueue.MailQueueException e) { + throw new RuntimeException(e); + } + } +} http://git-wip-us.apache.org/repos/asf/james-project/blob/4097211f/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesTest.java ---------------------------------------------------------------------- diff --git a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesTest.java b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesTest.java index 705a90d..3add507 100644 --- a/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailqueue/src/test/java/org/apache/james/webadmin/routes/MailQueueRoutesTest.java @@ -32,7 +32,6 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; - import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; import java.util.List; @@ -49,14 +48,16 @@ import org.apache.james.task.MemoryTaskManager; import org.apache.james.task.TaskManager; import org.apache.james.webadmin.WebAdminServer; import org.apache.james.webadmin.WebAdminUtils; +import org.apache.james.webadmin.service.ClearMailQueueTask; import org.apache.james.webadmin.service.DeleteMailsFromMailQueueTask; import org.apache.james.webadmin.utils.JsonTransformer; import org.apache.mailet.Mail; import org.apache.mailet.base.test.FakeMail; import org.eclipse.jetty.http.HttpStatus; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; import com.github.steveash.guavate.Guavate; import com.jayway.restassured.RestAssured; @@ -106,7 +107,7 @@ public class MailQueueRoutesTest { .build(); } - @Before + @BeforeEach public void setUp() throws Exception { mailQueueFactory = new MemoryMailQueueFactory(new RawMailQueueItemDecoratorFactory()); webAdminServer = createServer(mailQueueFactory); @@ -114,765 +115,896 @@ public class MailQueueRoutesTest { RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); } - @After + @AfterEach public void tearDown() { webAdminServer.destroy(); } - @Test - public void listAllMailQueuesShouldReturnEmptyWhenNone() { - List<String> actual = when() - .get() - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .extract() - .body() - .jsonPath() - .getList("."); - - assertThat(actual).isEmpty(); - } - - @Test - public void listAllMailQueuesShouldReturnSingleElementListWhenOnlyOneMailQueue() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - List<String> actual = when() - .get() - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .extract() - .body() - .jsonPath() - .getList("."); - - assertThat(actual).containsOnly(FIRST_QUEUE); - } - - @Test - public void listAllMailQueuesShouldReturnListWhenSeveralMailQueues() { - mailQueueFactory.createQueue(FIRST_QUEUE); - mailQueueFactory.createQueue(SECOND_QUEUE); - mailQueueFactory.createQueue(THIRD_QUEUE); - mailQueueFactory.createQueue(FOURTH_QUEUE); - - List<String> actual = when() - .get() - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .extract() - .body() - .jsonPath() - .getList("."); - - assertThat(actual).containsOnly(FIRST_QUEUE, SECOND_QUEUE, THIRD_QUEUE, FOURTH_QUEUE); - } - - @Test - public void getMailQueueShouldReturnTheMailQueueDataWhenMailQueueExists() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - queue.enQueue(Mails.defaultMail().build()); - - when() - .get(FIRST_QUEUE) - .then() - .statusCode(HttpStatus.OK_200) - .body("name", equalTo(FIRST_QUEUE)) - .body("size", equalTo(1)); - } - - @Test - public void getMailQueueShouldReturnNotFoundWhenMailQueueDoesntExist() { - when() - .get(FIRST_QUEUE) - .then() - .statusCode(HttpStatus.NOT_FOUND_404); - } - - @Test - public void listMailsShouldReturnEmptyListWhenNoMails() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", empty()); - } - - @Test - public void listMailsShouldReturnMailsWhenSome() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - queue.enQueue(Mails.defaultMail().build()); - queue.enQueue(Mails.defaultMail().build()); - - when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", hasSize(2)); - } - - @Test - public void listMailsShouldReturnMailDetailsWhenSome() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail); - - String firstMail = "[0]"; - List<String> expectedRecipients = mail.getRecipients().stream() - .map(MailAddress::asString) - .collect(Guavate.toImmutableList()); - - when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", hasSize(1)) - .body(firstMail + ".name", equalTo(mail.getName())) - .body(firstMail + ".sender", equalTo(mail.getSender().asString())) - .body(firstMail + ".recipients", equalTo(expectedRecipients)); - } - - @Test - public void listMailsShouldReturnEmptyWhenNoDelayedMailsAndAskFor() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail); - - given() - .param("delayed", "true") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", empty()); - } - - @Test - public void listMailsShouldReturnCurrentMailsWhenMailsAndAskForNotDelayed() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail); - - given() - .param("delayed", "false") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", hasSize(1)); - } - - @Test - public void listMailsShouldReturnDelayedMailsWhenAskFor() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail, 10, TimeUnit.MINUTES); - - given() - .param("delayed", "true") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", hasSize(1)); - } - - @Test - public void listMailsShouldReturnOneMailWhenMailsAndAskForALimitOfOne() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail); - queue.enQueue(mail); - queue.enQueue(mail); - - given() - .param("limit", "1") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.OK_200) - .contentType(ContentType.JSON) - .body(".", hasSize(1)); - } - - @Test - public void listMailsShouldReturnBadRequestWhenLimitIsLessThanZero() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .param("limit", "-1") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void listMailsShouldReturnBadRequestWhenLimitEqualsToZero() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .param("limit", "0") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void listMailsShouldReturnBadRequestWhenLimitIsInvalid() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .param("limit", "abc") - .when() - .get(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void deleteMailsShouldReturnNotFoundWhenMailQueueDoesntExist() { - when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.NOT_FOUND_404); - } - - @Test - public void deleteMailsShouldReturnBadRequestWhenSenderIsInvalid() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .param("sender", "123") - .when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void deleteMailsShouldReturnBadRequestWhenRecipientIsInvalid() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .param("recipient", "123") - .when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void deleteMailsTasksShouldCompleteWhenSenderIsValid() throws Exception{ - mailQueueFactory.createQueue(FIRST_QUEUE); - - String taskId = with() - .param("sender", SENDER_1_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - } - - @Test - public void deleteMailsShouldCompleteWhenNameIsValid() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - String taskId = with() - .param("name", "mailName") - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - } - - @Test - public void deleteMailsShouldCompleteWhenRecipientIsValid() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - String taskId = with() - .param("recipient", RECIPIENT_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - } - - @Test - public void deleteMailsShouldReturnBadRequestWhenNoQueryParameters() { - mailQueueFactory.createQueue(FIRST_QUEUE); - - when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void forcingDelayedMailsDeliveryShouldReturnNoContent() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "true") - .body("{\"delayed\": \"false\"}") - .when() - .patch(FIRST_QUEUE + "/mails") + @Nested + class ListMail { + + @Nested + class DataValidation { + @Test + public void listMailsShouldReturnBadRequestWhenLimitIsLessThanZero() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .param("limit", "-1") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void listMailsShouldReturnBadRequestWhenLimitEqualsToZero() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .param("limit", "0") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void listMailsShouldReturnBadRequestWhenLimitIsInvalid() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .param("limit", "abc") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + } + + @Nested + class HttpBodies { + + @Test + public void listAllMailQueuesShouldReturnEmptyWhenNone() { + List<String> actual = when() + .get() + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .extract() + .body() + .jsonPath() + .getList("."); + + assertThat(actual).isEmpty(); + } + + @Test + public void listAllMailQueuesShouldReturnSingleElementListWhenOnlyOneMailQueue() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + List<String> actual = when() + .get() + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .extract() + .body() + .jsonPath() + .getList("."); + + assertThat(actual).containsOnly(FIRST_QUEUE); + } + + @Test + public void listAllMailQueuesShouldReturnListWhenSeveralMailQueues() { + mailQueueFactory.createQueue(FIRST_QUEUE); + mailQueueFactory.createQueue(SECOND_QUEUE); + mailQueueFactory.createQueue(THIRD_QUEUE); + mailQueueFactory.createQueue(FOURTH_QUEUE); + + List<String> actual = when() + .get() + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .extract() + .body() + .jsonPath() + .getList("."); + + assertThat(actual).containsOnly(FIRST_QUEUE, SECOND_QUEUE, THIRD_QUEUE, FOURTH_QUEUE); + } + + @Test + public void listMailsShouldReturnEmptyListWhenNoMails() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", empty()); + } + + @Test + public void listMailsShouldReturnMailsWhenSome() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + queue.enQueue(Mails.defaultMail().build()); + queue.enQueue(Mails.defaultMail().build()); + + when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", hasSize(2)); + } + + @Test + public void listMailsShouldReturnMailDetailsWhenSome() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail); + + String firstMail = "[0]"; + List<String> expectedRecipients = mail.getRecipients().stream() + .map(MailAddress::asString) + .collect(Guavate.toImmutableList()); + + when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", hasSize(1)) + .body(firstMail + ".name", equalTo(mail.getName())) + .body(firstMail + ".sender", equalTo(mail.getSender().asString())) + .body(firstMail + ".recipients", equalTo(expectedRecipients)); + } + + @Test + public void listMailsShouldReturnEmptyWhenNoDelayedMailsAndAskFor() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail); + + given() + .param("delayed", "true") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", empty()); + } + + @Test + public void listMailsShouldReturnCurrentMailsWhenMailsAndAskForNotDelayed() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail); + + given() + .param("delayed", "false") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", hasSize(1)); + } + + @Test + public void listMailsShouldReturnDelayedMailsWhenAskFor() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail, 10, TimeUnit.MINUTES); + + given() + .param("delayed", "true") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", hasSize(1)); + } + + @Test + public void listMailsShouldReturnOneMailWhenMailsAndAskForALimitOfOne() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail); + queue.enQueue(mail); + queue.enQueue(mail); + + given() + .param("limit", "1") + .when() + .get(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.OK_200) + .contentType(ContentType.JSON) + .body(".", hasSize(1)); + } + } + } + + @Nested + class GetMailQueue { + + @Test + public void getMailQueueShouldReturnTheMailQueueDataWhenMailQueueExists() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + queue.enQueue(Mails.defaultMail().build()); + + when() + .get(FIRST_QUEUE) .then() - .statusCode(HttpStatus.NO_CONTENT_204); - } - - @Test - public void forcingDelayedMailsDeliveryForUnknownQueueShouldReturnNotFound() throws Exception { - given() - .queryParam("delayed", "true") - .body("{\"delayed\": \"false\"}") - .when() - .patch("unknown queue" + "/mails") + .statusCode(HttpStatus.OK_200) + .body("name", equalTo(FIRST_QUEUE)) + .body("size", equalTo(1)); + } + + @Test + public void getMailQueueShouldReturnNotFoundWhenMailQueueDoesntExist() { + when() + .get(FIRST_QUEUE) .then() - .statusCode(HttpStatus.NOT_FOUND_404); - } - - @Test - public void forcingDelayedMailsDeliveryRequiresDelayedParameter() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .body("{\"delayed\": \"false\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void forcingDelayedMailsDeliveryShouldRejectFalseDelayedParam() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "false") - .body("{\"delayed\": \"false\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void forcingDelayedMailsDeliveryShouldRejectNonBooleanDelayedParam() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "wrong") - .body("{\"delayed\": \"false\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void forcingDelayedMailsDeliveryShouldRejectRequestWithoutBody() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "true") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } - - @Test - public void deleteMailsShouldDeleteMailsWhenSenderIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .sender(SENDER_1_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .sender(SENDER_2_JAMES_ORG) - .build()); - - String taskId = with() - .param("sender", SENDER_1_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - - assertThat(queue.browse()) - .hasSize(1) - .first() - .satisfies(mailView -> assertThat(mailView.getMail().getName()).isEqualTo(FAKE_MAIL_NAME_2)); - } - - @Test - public void deleteMailsShouldDeleteMailsWhenNameIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .build()); - - String taskId = with() - .param("name", FAKE_MAIL_NAME_1) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - - assertThat(queue.browse()) - .hasSize(1) - .first() - .satisfies(mailView -> assertThat(mailView.getMail().getName()).isEqualTo(FAKE_MAIL_NAME_2)); - } - - @Test - public void deleteMailsShouldDeleteMailsWhenRecipientIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .recipient(RECIPIENT_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .recipient(RECIPIENT_1_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_3) - .recipient(RECIPIENT_2_JAMES_ORG) - .build()); - - String taskId = with() - .param("recipient", RECIPIENT_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - - assertThat(queue.browse()) - .hasSize(2) - .extracting(ManageableMailQueue.MailQueueItemView::getMail) - .extracting(Mail::getName) - .contains(FAKE_MAIL_NAME_2, FAKE_MAIL_NAME_3); - } - - @Test - public void deleteMailsTasksShouldHaveDetailsWhenSenderIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .sender(SENDER_1_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .sender(SENDER_2_JAMES_ORG) - .build()); - - String taskId = with() - .param("sender", SENDER_1_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")) - .body("taskId", is(notNullValue())) - .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) - .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) - .body("additionalInformation.initialCount", is(2)) - .body("additionalInformation.remainingCount", is(1)) - .body("additionalInformation.sender", is(SENDER_1_JAMES_ORG)) - .body("startedDate", is(notNullValue())) - .body("submitDate", is(notNullValue())) - .body("completedDate", is(notNullValue())); - } + .statusCode(HttpStatus.NOT_FOUND_404); + } + } + + @Nested + class ForceDelayedMailsDelivery { + + @Nested + class DataValidation { + + @Test + public void forcingDelayedMailsDeliveryShouldReturnNoContent() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "true") + .body("{\"delayed\": \"false\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.NO_CONTENT_204); + } + + @Test + public void forcingDelayedMailsDeliveryForUnknownQueueShouldReturnNotFound() throws Exception { + given() + .queryParam("delayed", "true") + .body("{\"delayed\": \"false\"}") + .when() + .patch("unknown queue" + "/mails") + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void forcingDelayedMailsDeliveryRequiresDelayedParameter() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .body("{\"delayed\": \"false\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectFalseDelayedParam() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "false") + .body("{\"delayed\": \"false\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectNonBooleanDelayedParam() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "wrong") + .body("{\"delayed\": \"false\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectRequestWithoutBody() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "true") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectRequestWithoutDelayedParameter() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "true") + .body("{\"xx\": \"false\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldAcceptRequestWithUnknownFields() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "true") + .body("{" + + "\"xx\": \"false\"," + + "\"delayed\": \"false\"" + + "}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectMalformedJsonPayload() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "true") + .body("{\"xx\":") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectTrueDelayedAttribute() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "false") + .body("{\"delayed\": \"true\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void forcingDelayedMailsDeliveryShouldRejectStringDelayedAttribute() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .queryParam("delayed", "false") + .body("{\"delayed\": \"string\"}") + .when() + .patch(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + } + + @Nested + class SideEffects { + @Test + public void forcingDelayedMailsDeliveryShouldActuallyChangePropertyOnMails() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + FakeMail mail = Mails.defaultMail().build(); + queue.enQueue(mail, 10L, TimeUnit.MINUTES); + queue.enQueue(mail, 10L, TimeUnit.MINUTES); + queue.enQueue(mail); + + with() + .queryParam("delayed", "true") + .body("{\"delayed\": \"false\"}") + .then() + .patch(FIRST_QUEUE + "/mails"); + + assertThat(queue.browse()) + .extracting(ManageableMailQueue.MailQueueItemView::getNextDelivery) + .hasSize(3) + .allSatisfy((delivery) -> { + assertThat(delivery).isNotEmpty(); + assertThat(delivery.get()).isBefore(ZonedDateTime.now()); + }); + } + } + } + + @Nested + class DeleteMail { + + @Nested + class DataValidation { + + @Test + public void deleteMailsShouldReturnNotFoundWhenMailQueueDoesntExist() { + when() + .delete(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void deleteMailsShouldReturnBadRequestWhenSenderIsInvalid() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .param("sender", "123") + .when() + .delete(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void deleteMailsShouldReturnBadRequestWhenRecipientIsInvalid() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + given() + .param("recipient", "123") + .when() + .delete(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void deleteMailsShouldReturnBadRequestWhenAllParametersAreGiven() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + given() + .param("sender", "sen...@james.org") + .param("name", "mailName") + .param("recipient", "recipi...@james.org") + .when() + .delete(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + + @Test + public void deleteMailsShouldReturnBadRequestWhenTwoParametersAreGiven() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + given() + .param("sender", "sen...@james.org") + .param("name", "mailName") + .when() + .delete(FIRST_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.BAD_REQUEST_400); + } + } + + @Nested + class HttpBodies { + + @Test + public void deleteMailsTasksShouldCompleteWhenSenderIsValid() throws Exception{ + mailQueueFactory.createQueue(FIRST_QUEUE); + + String taskId = with() + .param("sender", SENDER_1_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + } + + @Test + public void deleteMailsShouldCompleteWhenNameIsValid() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + String taskId = with() + .param("name", "mailName") + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + } + + @Test + public void deleteMailsShouldCompleteWhenRecipientIsValid() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + String taskId = with() + .param("recipient", RECIPIENT_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + } + + @Test + public void deleteMailsTasksShouldHaveDetailsWhenSenderIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .sender(SENDER_1_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .sender(SENDER_2_JAMES_ORG) + .build()); + + String taskId = with() + .param("sender", SENDER_1_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) + .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) + .body("additionalInformation.initialCount", is(2)) + .body("additionalInformation.remainingCount", is(1)) + .body("additionalInformation.sender", is(SENDER_1_JAMES_ORG)) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + public void deleteMailsTasksShouldHaveDetailsWhenNameIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .build()); + + String taskId = with() + .param("name", FAKE_MAIL_NAME_1) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) + .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) + .body("additionalInformation.initialCount", is(2)) + .body("additionalInformation.remainingCount", is(1)) + .body("additionalInformation.name", is(FAKE_MAIL_NAME_1)) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + public void deleteMailsTasksShouldHaveDetailsWhenRecipientIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .recipient(RECIPIENT_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .recipient(RECIPIENT_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .recipient(RECIPIENT_1_JAMES_ORG) + .build()); + + String taskId = with() + .param("recipient", RECIPIENT_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) + .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) + .body("additionalInformation.initialCount", is(3)) + .body("additionalInformation.remainingCount", is(1)) + .body("additionalInformation.recipient", is(RECIPIENT_JAMES_ORG)) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + } + + @Nested + class SideEffects { + + @Test + public void deleteMailsShouldDeleteMailsWhenSenderIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .sender(SENDER_1_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .sender(SENDER_2_JAMES_ORG) + .build()); + + String taskId = with() + .param("sender", SENDER_1_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + + assertThat(queue.browse()) + .hasSize(1) + .first() + .satisfies(mailView -> assertThat(mailView.getMail().getName()).isEqualTo(FAKE_MAIL_NAME_2)); + } + + @Test + public void deleteMailsShouldDeleteMailsWhenNameIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .build()); + + String taskId = with() + .param("name", FAKE_MAIL_NAME_1) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + + assertThat(queue.browse()) + .hasSize(1) + .first() + .satisfies(mailView -> assertThat(mailView.getMail().getName()).isEqualTo(FAKE_MAIL_NAME_2)); + } + + @Test + public void deleteMailsShouldDeleteMailsWhenRecipientIsGiven() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .recipient(RECIPIENT_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .recipient(RECIPIENT_1_JAMES_ORG) + .build()); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_3) + .recipient(RECIPIENT_2_JAMES_ORG) + .build()); + + String taskId = with() + .param("recipient", RECIPIENT_JAMES_ORG) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + + assertThat(queue.browse()) + .hasSize(2) + .extracting(ManageableMailQueue.MailQueueItemView::getMail) + .extracting(Mail::getName) + .contains(FAKE_MAIL_NAME_2, FAKE_MAIL_NAME_3); + } + + @Test + public void deleteMailsShouldDeleteMailsWhenTheyAreMatching() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + String recipient = "recipi...@james.org"; + queue.enQueue(Mails.defaultMail() + .recipient(recipient) + .build()); + queue.enQueue(Mails.defaultMail().build()); + queue.enQueue(Mails.defaultMail().build()); + + String taskId = with() + .param("recipient", recipient) + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + + MailAddress deletedRecipientMailAddress = new MailAddress(recipient); + assertThat(queue.browse()) + .hasSize(2) + .allSatisfy((ManageableMailQueue.MailQueueItemView item) -> { + assertThat(item.getMail().getRecipients()).doesNotContain(deletedRecipientMailAddress); + }); + } + } + } + + @Nested + class ClearMail { + + @Test + public void clearMailQueueShouldReturnNotFoundWhenMailQueueDoesNotExist() throws Exception { + mailQueueFactory.createQueue(FIRST_QUEUE); + + when() + .delete(SECOND_QUEUE + "/mails") + .then() + .statusCode(HttpStatus.NOT_FOUND_404); + } + + @Test + public void clearMailQueueShouldCompleteWhenNoQueryParameters() { + mailQueueFactory.createQueue(FIRST_QUEUE); + + String taskId = with() + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); + } - @Test - public void deleteMailsTasksShouldHaveDetailsWhenNameIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .build()); - - String taskId = with() - .param("name", FAKE_MAIL_NAME_1) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")) - .body("taskId", is(notNullValue())) - .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) - .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) - .body("additionalInformation.initialCount", is(2)) - .body("additionalInformation.remainingCount", is(1)) - .body("additionalInformation.name", is(FAKE_MAIL_NAME_1)) - .body("startedDate", is(notNullValue())) - .body("submitDate", is(notNullValue())) - .body("completedDate", is(notNullValue())); - } + @Test + public void clearMailQueueShouldHaveDetailsWhenNoQueryParameters() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - @Test - public void deleteMailsTasksShouldHaveDetailsWhenRecipientIsGiven() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_1) - .recipient(RECIPIENT_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .recipient(RECIPIENT_JAMES_ORG) - .build()); - - queue.enQueue(FakeMail.builder() - .name(FAKE_MAIL_NAME_2) - .recipient(RECIPIENT_1_JAMES_ORG) - .build()); - - String taskId = with() - .param("recipient", RECIPIENT_JAMES_ORG) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")) - .body("taskId", is(notNullValue())) - .body("type", is(DeleteMailsFromMailQueueTask.TYPE)) - .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) - .body("additionalInformation.initialCount", is(3)) - .body("additionalInformation.remainingCount", is(1)) - .body("additionalInformation.recipient", is(RECIPIENT_JAMES_ORG)) - .body("startedDate", is(notNullValue())) - .body("submitDate", is(notNullValue())) - .body("completedDate", is(notNullValue())); - } + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .build()); - @Test - public void deleteMailsShouldReturnBadRequestWhenAllParametersAreGiven() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - given() - .param("sender", "sen...@james.org") - .param("name", "mailName") - .param("recipient", "recipi...@james.org") - .when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .build()); - @Test - public void forcingDelayedMailsDeliveryShouldRejectRequestWithoutDelayedParameter() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "true") - .body("{\"xx\": \"false\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_3) + .build()); - @Test - public void forcingDelayedMailsDeliveryShouldAcceptRequestWithUnknownFields() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "true") - .body("{" + - "\"xx\": \"false\"," + - "\"delayed\": \"false\"" + - "}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + String taskId = with() + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); - @Test - public void forcingDelayedMailsDeliveryShouldRejectMalformedJsonPayload() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "true") - .body("{\"xx\":") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("type", is(ClearMailQueueTask.TYPE)) + .body("additionalInformation.mailQueueName", is(FIRST_QUEUE)) + .body("additionalInformation.initialCount", is(3)) + .body("additionalInformation.remainingCount", is(0)) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + public void clearMailQueueShouldDeleteAllMailsInQueueWhenNoQueryParameters() throws Exception { + MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); + + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_1) + .build()); - @Test - public void forcingDelayedMailsDeliveryShouldRejectTrueDelayedAttribute() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "false") - .body("{\"delayed\": \"true\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_2) + .build()); - @Test - public void deleteMailsShouldReturnBadRequestWhenTwoParametersAreGiven() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - given() - .param("sender", "sen...@james.org") - .param("name", "mailName") - .when() - .delete(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + queue.enQueue(FakeMail.builder() + .name(FAKE_MAIL_NAME_3) + .build()); - @Test - public void forcingDelayedMailsDeliveryShouldRejectStringDelayedAttribute() throws Exception { - mailQueueFactory.createQueue(FIRST_QUEUE); - - given() - .queryParam("delayed", "false") - .body("{\"delayed\": \"string\"}") - .when() - .patch(FIRST_QUEUE + "/mails") - .then() - .statusCode(HttpStatus.BAD_REQUEST_400); - } + String taskId = with() + .delete(FIRST_QUEUE + "/mails") + .jsonPath() + .getString("taskId"); - @Test - public void deleteMailsShouldDeleteMailsWhenTheyAreMatching() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - String recipient = "recipi...@james.org"; - queue.enQueue(Mails.defaultMail() - .recipient(recipient) - .build()); - queue.enQueue(Mails.defaultMail().build()); - queue.enQueue(Mails.defaultMail().build()); - - String taskId = with() - .param("recipient", recipient) - .delete(FIRST_QUEUE + "/mails") - .jsonPath() - .getString("taskId"); - - given() - .basePath(TasksRoutes.BASE) - .when() - .get(taskId + "/await") - .then() - .body("status", is("completed")); - - MailAddress deletedRecipientMailAddress = new MailAddress(recipient); - assertThat(queue.browse()) - .hasSize(2) - .allSatisfy((ManageableMailQueue.MailQueueItemView item) -> { - assertThat(item.getMail().getRecipients()).doesNotContain(deletedRecipientMailAddress); - }); - } + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")); - @Test - public void forcingDelayedMailsDeliveryShouldActuallyChangePropertyOnMails() throws Exception { - MemoryMailQueue queue = mailQueueFactory.createQueue(FIRST_QUEUE); - FakeMail mail = Mails.defaultMail().build(); - queue.enQueue(mail, 10L, TimeUnit.MINUTES); - queue.enQueue(mail, 10L, TimeUnit.MINUTES); - queue.enQueue(mail); - - with() - .queryParam("delayed", "true") - .body("{\"delayed\": \"false\"}") - .then() - .patch(FIRST_QUEUE + "/mails"); - - assertThat(queue.browse()) - .extracting(ManageableMailQueue.MailQueueItemView::getNextDelivery) - .hasSize(3) - .allSatisfy((delivery) -> { - assertThat(delivery).isNotEmpty(); - assertThat(delivery.get()).isBefore(ZonedDateTime.now()); - }); + assertThat(queue.getSize()).isEqualTo(0); + } } } http://git-wip-us.apache.org/repos/asf/james-project/blob/4097211f/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 423204f..9702753 100644 --- a/src/site/markdown/server/manage-webadmin.md +++ b/src/site/markdown/server/manage-webadmin.md @@ -21,26 +21,26 @@ In case of any error, the system will return an error message which is json form ## Navigation menu - - [Administrating domains](#Administrating_domains) - - [Administrating users](#Administrating_users) - - [Administrating user mailboxes](#Administrating_user_mailboxes) - - [Administrating quotas by users](#Administrating_quotas_by_users) - - [Administrating quotas by domains](#Administrating_quotas_by_domains) - - [Administrating global quotas](#Administrating_global_quotas) - - [Cassandra Schema upgrades](#Cassandra_Schema_upgrades) - - [Correcting ghost mailbox](#Correcting_ghost_mailbox) - - [Creating address group](#Creating_address_group) - - [Creating address forwards](#Creating_address_forwards) - - [Administrating mail repositories](#Administrating_mail_repositories) - - [Administrating mail queues](#Administrating_mail_queues) - - [Task management](#Task_management) + - [Administrating domains](#administrating-domains) + - [Administrating users](#administrating-users) + - [Administrating user mailboxes](#administrating-user-mailboxes) + - [Administrating quotas by users](#administrating-quotas-by-users) + - [Administrating quotas by domains](#administrating-quotas-by-domains) + - [Administrating global quotas](#administrating-global-quotas) + - [Cassandra Schema upgrades](#cassandra-schema-upgrades) + - [Correcting ghost mailbox](#correcting-ghost-mailbox) + - [Creating address group](#creating-address-group) + - [Creating address forwards](#creating-address-forwards) + - [Administrating mail repositories](#administrating-mail-repositories) + - [Administrating mail queues](#administrating-mail-queues) + - [Task management](#task-management) ## Administrating domains - - [Create a domain](#Create_a_domain) - - [Delete a domain](#Delete_a_domain) - - [Test if a domain exists](#Test_if_a_domain_exists) - - [Get the list of domains](#Get_the_list_of_domains) + - [Create a domain](#create-a-domain) + - [Delete a domain](#delete-a-domain) + - [Test if a domain exists](#test-if-a-domain-exists) + - [Get the list of domains](#get-the-list-of-domains) ### Create a domain @@ -103,10 +103,10 @@ Response codes: ## Administrating users - - [Create a user](#Create_a_user) - - [Updating a user password](#Updating_a_user_password) - - [Deleting a domain](#Deleting_a_user) - - [Retrieving the user list](#Retrieving_the_user_list) + - [Create a user](#create-a-user) + - [Updating a user password](#updating-a-user-password) + - [Deleting a domain](#deleting-a-user) + - [Retrieving the user list](#retrieving-the-user-list) ### Create a user @@ -165,11 +165,11 @@ Response codes: ## Administrating user mailboxes - - [Creating a mailbox](#Creating_a_mailbox) - - [Deleting a mailbox and its children](#Deleting_a_mailbox_and_its_children) - - [Testing existence of a mailbox](#Testing_existence_of_a_mailbox) - - [Listing user mailboxes](#Listing_user_mailboxes) - - [Deleting_user_mailboxes](#Deleting_user_mailboxes) + - [Creating a mailbox](#creating-a-mailbox) + - [Deleting a mailbox and its children](#deleting-a-mailbox-and-its-children) + - [Testing existence of a mailbox](#testing-existence-of-a-mailbox) + - [Listing user mailboxes](#listing-user-mailboxes) + - [Deleting_user_mailboxes](#deleting-user-mailboxes) ### Creating a mailbox @@ -261,14 +261,14 @@ Response codes: ## Administrating quotas by users - - [Getting the quota for a user](#Getting_the_quota_for_a_user) - - [Updating the quota for a user](#Updating_the_quota_for_a_user) - - [Getting the quota count for a user](#Getting_the_quota_count_for_a_user) - - [Updating the quota count for a user](#Updating_the_quota_count_for_a_user) - - [Deleting the quota count for a user](#Deleting_the_quota_count_for_a_user) - - [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) + - [Getting the quota for a user](#getting-the-quota-for-a-user) + - [Updating the quota for a user](#updating-the-quota-for-a-user) + - [Getting the quota count for a user](#getting-the-quota-count-for-a-user) + - [Updating the quota count for a user](#updating-the-quota-count-for-a-user) + - [Deleting the quota count for a user](#deleting-the-quota-count-for-a-user) + - [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) ### Getting the quota for a user @@ -476,14 +476,14 @@ Response codes: ## 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_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) - - [Updating the quota size for a domain](#Updating_the_quota_size_for_a_domain) - - [Deleting the quota size for a domain](#Deleting_the_quota_size_for_a_domain) + - [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) + - [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) + - [Updating the quota size for a domain](#updating-the-quota-size-for-a-domain) + - [Deleting the quota size for a domain](#deleting-the-quota-size-for-a-domain) ### Getting the quota for a domain @@ -664,14 +664,14 @@ Response codes: ## Administrating global quotas - - [Getting the global quota](#Getting_the_global_quota) - - [Updating global quota](#Updating_global_quota) - - [Getting the global quota count](#Getting_the_global_quota_count) - - [Updating the global quota count](#Updating_the_global_quota_count) - - [Deleting the global quota count](#Deleting_the_global_quota_count) - - [Getting the global quota size](#Getting_the_global_quota_size) - - [Updating the global quota size](#Updating_the_global_quota_size) - - [Deleting the global quota size](#Deleting_the_global_quota_size) + - [Getting the global quota](#getting-the-global-quota) + - [Updating global quota](#updating-global-quota) + - [Getting the global quota count](#getting-the-global-quota-count) + - [Updating the global quota count](#updating-the-global-quota-count) + - [Deleting the global quota count](#deleting-the-global-quota-count) + - [Getting the global quota size](#getting-the-global-quota-size) + - [Updating the global quota size](#updating-the-global-quota-size) + - [Deleting the global quota size](#deleting-the-global-quota-size) ### Getting the global quota @@ -847,10 +847,10 @@ 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) - - [Upgrading to a specific version](#Upgrading_to_a_specific_version) - - [Upgrading to the latest version](#Upgrading_to_the_latest_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) ### Retrieving current Cassandra schema version @@ -1019,10 +1019,10 @@ to be configured. Note that email addresses are restricted to ASCII character set. Mail addresses not matching this criteria will be rejected. - - [Listing groups](#Listing_groups) - - [Listing members of a group](#Listing_members_of_a_group) - - [Adding a group member](#Adding_a_group_member) - - [Removing a group member](#Removing_a_group_member) + - [Listing groups](#listing-groups) + - [Listing members of a group](#listing-members-of-a-group) + - [Adding a group member](#adding-a-group-member) + - [Removing a group member](#removing-a-group-member) ### Listing groups @@ -1107,10 +1107,10 @@ to be configured. Note that email addresses are restricted to ASCII character set. Mail addresses not matching this criteria will be rejected. - - [Listing Forwards](#Listing_Forwards) - - [Listing destinations in a forward](#Listing_destinations_in_a_forward) - - [Adding a new destination to a forward](#Adding_a_new_destination_to_a_forward) - - [Removing a destination of a forward](#Removing_a_destination_of_a_forward) + - [Listing Forwards](#listing-forwards) + - [Listing destinations in a forward](#listing-destinations-in-a-forward) + - [Adding a new destination to a forward](#adding-a-new-destination-to-a-forward) + - [Removing a destination of a forward](#removing-a-destination-of-a-forward) ### Listing Forwards @@ -1183,14 +1183,14 @@ Response codes: ## Administrating mail repositories - - [Listing mail repositories](#Listing_mail_repositories) - - [Getting additional information for a mail repository](#Getting_additional_information_for_a_mail_repository) - - [Listing mails contained in a mail repository](#Listing_mails_contained_in_a_mail_repository) - - [Reading a mail details](#Reading_a_mail_details) - - [Removing a mail from a mail repository](#Removing_a_mail_from_a_mail_repository) - - [Removing all mails from a mail repository](#Removing_all_mails_from_a_mail_repository) - - [Reprocessing mails from a mail repository](#Reprocessing_mails_from_a_mail_repository) - - [Reprocessing a specific mail from a mail repository](#Reprocessing_a_specific_mail_from_a_mail_repository) + - [Listing mail repositories](#listing-mail-repositories) + - [Getting additional information for a mail repository](#getting-additional-information-for-a-mail-repository) + - [Listing mails contained in a mail repository](#listing-mails-contained-in-a-mail-repository) + - [Reading a mail details](#reading-a-mail-details) + - [Removing a mail from a mail repository](#removing-a-mail-from-a-mail-repository) + - [Removing all mails from a mail repository](#removing-all-mails-from-a-mail-repository) + - [Reprocessing mails from a mail repository](#reprocessing-mails-from-a-mail-repository) + - [Reprocessing a specific mail from a mail repository](#reprocessing-a-specific-mail-from-a-mail-repository) ### Listing mail repositories @@ -1515,11 +1515,12 @@ The scheduled task will have the following type `reprocessingOneTask` and the fo ## Administrating mail queues - - [Listing mail queues](#Listing_mail_queues) - - [Getting a mail queue details](#Getting_a_mail_queue_details) - - [Listing the mails of a mail queue](#Listing_the_mails_of_a_mail_queue) - - [Deleting mails from a mail queue](#Deleting_mails_from_a_mail_queue) - - [Flushing mails from a mail queue](#Flushing_mails_from_a_mail_queue) + - [Listing mail queues](#listing-mail-queues) + - [Getting a mail queue details](#getting-a-mail-queue-details) + - [Listing the mails of a mail queue](#listing-the-mails-of-a-mail-queue) + - [Deleting mails from a mail queue](#deleting-mails-from-a-mail-queue) + - [Clearing a mail queue](#clearing-a-mail-queue) + - [Flushing mails from a mail queue](#flushing-mails-from-a-mail-queue) ### Listing mail queues @@ -1624,6 +1625,32 @@ The scheduled task will have the following type `deleteMailsFromMailQueue` and t } ``` +### Clearing a mail queue + +``` +curl -XDELETE http://ip:port/mailQueues/mailQueueName/mails +``` + +All mails from the given mail queue will be deleted. + + +Response codes: + + - 201: Success. Corresponding task id is returned. + - 400: Invalid request + - 404: The mail queue does not exist + - 500: Internal error + +The scheduled task will have the following type `clearMailQueue` and the following `additionalInformation`: + +``` +{ + "mailQueueName":"outgoing", + "initialCount":10, + "remainingCount": 0 +} +``` + ### Flushing mails from a mail queue ``` @@ -1650,10 +1677,10 @@ Some webadmin features schedules tasks. The task management API allow to monitor Note that the `taskId` used in the following APIs is returned by other WebAdmin APIs scheduling tasks. - - [Getting a task details](#Getting_a_task_details) - - [Awaiting a task](#Awaiting_a_task) - - [Cancelling a task](#Cancelling_a_task) - - [Listing tasks](#Listing_tasks) + - [Getting a task details](#getting-a-task-details) + - [Awaiting a task](#awaiting-a-task) + - [Cancelling a task](#cancelling-a-task) + - [Listing tasks](#listing-tasks) ### Getting a task details --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org