You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by ro...@apache.org on 2019/10/09 14:33:45 UTC

[james-project] 01/05: JAMES-2914 Add serialization integration tests for webadmin

This is an automated email from the ASF dual-hosted git repository.

rouazana pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit a4b7a1441c322e8484a140dbb8624a43d574c856
Author: Raphael Ouazana <ra...@linagora.com>
AuthorDate: Mon Oct 7 17:58:36 2019 +0200

    JAMES-2914 Add serialization integration tests for webadmin
---
 .../james/utils/MailRepositoryProbeImpl.java       |   3 +
 .../james/modules/EventDeadLettersProbe.java}      |  43 +-
 .../james/modules/mailbox/DefaultEventModule.java  |   3 +
 ...dminServerTaskSerializationIntegrationTest.java | 656 +++++++++++++++++++++
 .../routes/DeletedMessagesVaultDeleteTask.java     |   2 +-
 .../routes/DeletedMessagesVaultExportTask.java     |   4 +-
 .../routes/DeletedMessagesVaultRestoreTask.java    |   4 +-
 .../vault/routes/DeletedMessagesVaultRoutes.java   |   2 +-
 8 files changed, 677 insertions(+), 40 deletions(-)

diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
index b908450..312fb78 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
+++ b/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
@@ -61,4 +61,7 @@ public class MailRepositoryProbeImpl implements GuiceProbe {
             .collect(Guavate.toImmutableList());
     }
 
+    public MailRepositoryStore getMailRepositoryStore() {
+        return repositoryStore;
+    }
 }
\ No newline at end of file
diff --git a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/EventDeadLettersProbe.java
similarity index 50%
copy from server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
copy to server/container/guice/mailbox/src/main/java/org/apache/james/modules/EventDeadLettersProbe.java
index b908450..732040f 100644
--- a/server/container/guice/guice-common/src/main/java/org/apache/james/utils/MailRepositoryProbeImpl.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/EventDeadLettersProbe.java
@@ -17,48 +17,23 @@
  * under the License.                                           *
  ****************************************************************/
 
-package org.apache.james.utils;
-
-import java.util.List;
+package org.apache.james.modules;
 
 import javax.inject.Inject;
 
-import org.apache.james.mailrepository.api.MailKey;
-import org.apache.james.mailrepository.api.MailRepositoryStore;
-import org.apache.james.mailrepository.api.MailRepositoryUrl;
-
-import com.github.steveash.guavate.Guavate;
-import com.google.common.collect.ImmutableList;
+import org.apache.james.mailbox.events.EventDeadLetters;
+import org.apache.james.utils.GuiceProbe;
 
-public class MailRepositoryProbeImpl implements GuiceProbe {
+public class EventDeadLettersProbe implements GuiceProbe {
 
-    private final MailRepositoryStore repositoryStore;
+    private final EventDeadLetters eventDeadLetters;
 
     @Inject
-    public MailRepositoryProbeImpl(MailRepositoryStore repositoryStore) {
-        this.repositoryStore = repositoryStore;
+    public EventDeadLettersProbe(EventDeadLetters eventDeadLetters) {
+        this.eventDeadLetters = eventDeadLetters;
     }
 
-    /**
-     * Get the count of email currently stored in a given repository
-     */
-    public long getRepositoryMailCount(MailRepositoryUrl url) throws Exception {
-        return repositoryStore.select(url).size();
+    public EventDeadLetters getEventDeadLetters() {
+        return eventDeadLetters;
     }
-
-    public void createRepository(MailRepositoryUrl url) throws Exception {
-        repositoryStore.select(url);
-    }
-
-    public List<MailKey> listMailKeys(MailRepositoryUrl url) throws Exception {
-        return ImmutableList.copyOf(
-            repositoryStore.select(url)
-                .list());
-    }
-
-    public List<MailRepositoryUrl> listRepositoryUrls() {
-        return repositoryStore.getUrls()
-            .collect(Guavate.toImmutableList());
-    }
-
 }
\ No newline at end of file
diff --git a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/DefaultEventModule.java b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/DefaultEventModule.java
index 4d6eafd..a7114f9 100644
--- a/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/DefaultEventModule.java
+++ b/server/container/guice/mailbox/src/main/java/org/apache/james/modules/mailbox/DefaultEventModule.java
@@ -31,7 +31,9 @@ import org.apache.james.mailbox.events.MemoryEventDeadLetters;
 import org.apache.james.mailbox.events.RetryBackoffConfiguration;
 import org.apache.james.mailbox.events.delivery.EventDelivery;
 import org.apache.james.mailbox.events.delivery.InVmEventDelivery;
+import org.apache.james.modules.EventDeadLettersProbe;
 import org.apache.james.server.core.configuration.ConfigurationProvider;
+import org.apache.james.utils.GuiceProbe;
 import org.apache.james.utils.InitialisationOperation;
 
 import com.google.inject.AbstractModule;
@@ -52,6 +54,7 @@ public class DefaultEventModule extends AbstractModule {
         bind(MemoryEventDeadLetters.class).in(Scopes.SINGLETON);
 
         bind(EventDeadLetters.class).to(MemoryEventDeadLetters.class);
+        Multibinder.newSetBinder(binder(), GuiceProbe.class).addBinding().to(EventDeadLettersProbe.class);
         bind(MailboxListenersLoader.class).to(MailboxListenersLoaderImpl.class);
         bind(EventDelivery.class).to(InVmEventDelivery.class);
         bind(EventBus.class).to(InVMEventBus.class);
diff --git a/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerTaskSerializationIntegrationTest.java b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerTaskSerializationIntegrationTest.java
new file mode 100644
index 0000000..1baebe6
--- /dev/null
+++ b/server/protocols/webadmin-integration-test/src/test/java/org/apache/james/webadmin/integration/WebAdminServerTaskSerializationIntegrationTest.java
@@ -0,0 +1,656 @@
+/****************************************************************
+ * 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.integration;
+
+import static io.restassured.RestAssured.given;
+import static io.restassured.RestAssured.when;
+import static io.restassured.RestAssured.with;
+import static org.apache.james.webadmin.Constants.SEPARATOR;
+import static org.apache.james.webadmin.vault.routes.DeletedMessagesVaultRoutes.MESSAGE_PATH_PARAM;
+import static org.apache.james.webadmin.vault.routes.DeletedMessagesVaultRoutes.USERS;
+import static org.hamcrest.CoreMatchers.notNullValue;
+import static org.hamcrest.Matchers.is;
+
+import java.io.ByteArrayInputStream;
+import java.util.Date;
+import java.util.stream.Stream;
+
+import javax.mail.Flags;
+
+import org.apache.james.CassandraRabbitMQAwsS3JmapTestRule;
+import org.apache.james.DockerCassandraRule;
+import org.apache.james.GuiceJamesServer;
+import org.apache.james.core.User;
+import org.apache.james.core.builder.MimeMessageBuilder;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.cassandra.mail.task.MailboxMergingTask;
+import org.apache.james.mailbox.events.Event;
+import org.apache.james.mailbox.events.EventDeadLetters;
+import org.apache.james.mailbox.events.GenericGroup;
+import org.apache.james.mailbox.events.Group;
+import org.apache.james.mailbox.events.MailboxListener;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxConstants;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.probe.MailboxProbe;
+import org.apache.james.mailbox.store.event.EventFactory;
+import org.apache.james.mailrepository.api.MailRepository;
+import org.apache.james.mailrepository.api.MailRepositoryStore;
+import org.apache.james.mailrepository.api.MailRepositoryUrl;
+import org.apache.james.modules.EventDeadLettersProbe;
+import org.apache.james.modules.MailboxProbeImpl;
+import org.apache.james.probe.DataProbe;
+import org.apache.james.task.TaskManager;
+import org.apache.james.utils.DataProbeImpl;
+import org.apache.james.utils.MailRepositoryProbeImpl;
+import org.apache.james.utils.WebAdminGuiceProbe;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.routes.CassandraMailboxMergingRoutes;
+import org.apache.james.webadmin.routes.MailQueueRoutes;
+import org.apache.james.webadmin.routes.MailRepositoriesRoutes;
+import org.apache.james.webadmin.routes.TasksRoutes;
+import org.apache.james.webadmin.service.ClearMailQueueTask;
+import org.apache.james.webadmin.service.ClearMailRepositoryTask;
+import org.apache.james.webadmin.service.DeleteMailsFromMailQueueTask;
+import org.apache.james.webadmin.service.EventDeadLettersRedeliverTask;
+import org.apache.james.webadmin.service.ReprocessingAllMailsTask;
+import org.apache.james.webadmin.service.ReprocessingOneMailTask;
+import org.apache.james.webadmin.vault.routes.DeletedMessagesVaultDeleteTask;
+import org.apache.james.webadmin.vault.routes.DeletedMessagesVaultExportTask;
+import org.apache.james.webadmin.vault.routes.DeletedMessagesVaultRestoreTask;
+import org.apache.james.webadmin.vault.routes.DeletedMessagesVaultRoutes;
+import org.apache.mailbox.tools.indexer.FullReindexingTask;
+import org.apache.mailbox.tools.indexer.MessageIdReIndexingTask;
+import org.apache.mailbox.tools.indexer.SingleMailboxReindexingTask;
+import org.apache.mailbox.tools.indexer.SingleMessageReindexingTask;
+import org.apache.mailbox.tools.indexer.UserReindexingTask;
+import org.apache.mailet.base.test.FakeMail;
+
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.eclipse.jetty.http.HttpStatus;
+import org.hamcrest.Matchers;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class WebAdminServerTaskSerializationIntegrationTest {
+
+    private static final String DOMAIN = "domain";
+    private static final String USERNAME = "username@" + DOMAIN;
+
+    @Rule
+    public DockerCassandraRule cassandra = new DockerCassandraRule();
+
+    @Rule
+    public CassandraRabbitMQAwsS3JmapTestRule jamesTestRule = CassandraRabbitMQAwsS3JmapTestRule.defaultTestRule();
+
+    private GuiceJamesServer guiceJamesServer;
+    private DataProbe dataProbe;
+    private MailboxProbe mailboxProbe;
+
+    @Before
+    public void setUp() throws Exception {
+        guiceJamesServer = jamesTestRule.jmapServer(cassandra.getModule());
+        guiceJamesServer.start();
+        dataProbe = guiceJamesServer.getProbe(DataProbeImpl.class);
+        dataProbe.addDomain(DOMAIN);
+        WebAdminGuiceProbe webAdminGuiceProbe = guiceJamesServer.getProbe(WebAdminGuiceProbe.class);
+
+        mailboxProbe = guiceJamesServer.getProbe(MailboxProbeImpl.class);
+
+        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminGuiceProbe.getWebAdminPort())
+            .build();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+    }
+
+    @After
+    public void tearDown() {
+        guiceJamesServer.stop();
+    }
+
+    @Test
+    public void fullReindexingShouldCompleteWhenNoMail() {
+        String taskId = with()
+            .post("/mailboxes?task=reIndex")
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(notNullValue()))
+            .body("type", is(FullReindexingTask.FULL_RE_INDEXING.asString()));
+    }
+
+    @Test
+    public void deleteMailsFromMailQueueShouldCompleteWhenSenderIsValid() {
+        String firstMailQueue = with()
+                .basePath(MailQueueRoutes.BASE_URL)
+            .get()
+            .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .extract()
+                .body()
+                .jsonPath()
+                .getString("[0]");
+
+        String taskId = with()
+                .basePath(MailQueueRoutes.BASE_URL)
+                .param("sender", USERNAME)
+            .delete(firstMailQueue + "/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.asString()));
+    }
+
+    @Test
+    public void reprocessingAllMailsShouldComplete() {
+        String escapedRepositoryPath = with()
+                .basePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
+            .get()
+            .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .extract()
+                .body()
+                .jsonPath()
+                .getString("[0].path");
+
+        String taskId = with()
+                .basePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
+                .param("action", "reprocess")
+            .patch(escapedRepositoryPath + "/mails")
+            .then()
+                .statusCode(HttpStatus.CREATED_201)
+                .extract()
+                .jsonPath()
+                .getString("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(notNullValue()))
+            .body("type", is(ReprocessingAllMailsTask.TYPE.asString()));
+    }
+
+    @Test
+    public void reprocessingOneMailShouldCreateATask() throws Exception {
+        MailRepositoryStore mailRepositoryStore = guiceJamesServer.getProbe(MailRepositoryProbeImpl.class).getMailRepositoryStore();
+        Stream<MailRepositoryUrl> urls = mailRepositoryStore.getUrls();
+        MailRepositoryUrl mailRepositoryUrl = urls.findAny().get();
+        MailRepository repository = mailRepositoryStore.get(mailRepositoryUrl).get();
+
+        repository.store(FakeMail.builder()
+            .name("name1")
+            .mimeMessage(MimeMessageBuilder.mimeMessageBuilder().build())
+            .build());
+
+        String taskId = with()
+            .basePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
+            .param("action", "reprocess")
+        .patch(mailRepositoryUrl.urlEncoded() + "/mails/name1")
+        .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .getString("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("failed"))
+            .body("taskId", is(notNullValue()))
+            .body("type", is(ReprocessingOneMailTask.TYPE.asString()));
+    }
+
+    @Test
+    public void singleMessageReindexingShouldCompleteWhenMail() throws Exception {
+        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
+        ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
+                USERNAME,
+                MailboxPath.forUser(USERNAME, MailboxConstants.INBOX),
+                new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
+                new Date(),
+                false,
+                new Flags());
+
+        String taskId = with()
+            .post("/mailboxes/" + mailboxId.serialize() + "/mails/"
+                    + composedMessageId.getUid().asLong() + "?task=reIndex")
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(SingleMessageReindexingTask.MESSAGE_RE_INDEXING.asString()));
+    }
+
+    @Test
+    public void messageIdReIndexingShouldCompleteWhenMail() throws Exception {
+        mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
+        ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
+            USERNAME,
+            MailboxPath.forUser(USERNAME, MailboxConstants.INBOX),
+            new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
+            new Date(),
+            false,
+            new Flags());
+
+        String taskId = with()
+            .post("/messages/" + composedMessageId.getMessageId().serialize() + "?task=reIndex")
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(MessageIdReIndexingTask.TYPE.asString()));
+    }
+
+    @Test
+    public void userReindexingShouldComplete() {
+        String taskId = with()
+                .queryParam("user", USERNAME)
+                .queryParam("task", "reIndex")
+            .post("/mailboxes")
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(UserReindexingTask.USER_RE_INDEXING.asString()));
+    }
+
+    @Test
+    public void deletedMessageVaultRestoreShouldComplete() throws Exception {
+        dataProbe.addUser(USERNAME, "password");
+        String query =
+            "{" +
+                "  \"fieldName\": \"subject\"," +
+                "  \"operator\": \"contains\"," +
+                "  \"value\": \"subject contains\"" +
+                "}";
+
+        String taskId =
+            with()
+                .basePath(DeletedMessagesVaultRoutes.ROOT_PATH)
+                .queryParam("action", "restore")
+                .body(query)
+            .post(USERS + SEPARATOR + USERNAME)
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(DeletedMessagesVaultRestoreTask.TYPE.asString()));
+    }
+
+    @Test
+    public void deletedMessageVaultExportShouldComplete() throws Exception {
+        dataProbe.addUser(USERNAME, "password");
+        String query = "{" +
+            "\"combinator\": \"and\"," +
+            "\"criteria\": []" +
+            "}";
+
+        String taskId = with()
+            .basePath(DeletedMessagesVaultRoutes.ROOT_PATH)
+            .queryParam("action", "export")
+            .queryParam("exportTo", "exportTo@james.org")
+            .body(query)
+        .post(USERS + SEPARATOR + USERNAME)
+        .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(DeletedMessagesVaultExportTask.TYPE.asString()));
+    }
+
+    @Test
+    public void errorRecoveryIndexationShouldCompleteWhenNoMail() {
+        String taskId = with()
+            .post("/mailboxes?task=reIndex")
+            .jsonPath()
+            .get("taskId");
+
+        with()
+            .basePath(TasksRoutes.BASE)
+            .get(taskId + "/await");
+
+        String fixingTaskId = with()
+            .queryParam("reIndexFailedMessagesOf", taskId)
+            .queryParam("task", "reIndex")
+        .post("/mailboxes")
+        .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(fixingTaskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is("ErrorRecoveryIndexation"));
+    }
+
+    @Test
+    public void eventDeadLettersRedeliverShouldComplete() {
+        String taskId = with()
+            .queryParam("action", "reDeliver")
+        .post("/events/deadLetter")
+            .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(EventDeadLettersRedeliverTask.TYPE.asString()));
+
+    }
+
+    @Test
+    public void eventDeadLettersRedeliverShouldCreateATask() {
+        String uuid = "6e0dd59d-660e-4d9b-b22f-0354479f47b4";
+        String insertionUuid = "6e0dd59d-660e-4d9b-b22f-0354479f47b7";
+        Group group = new GenericGroup("a");
+        EventDeadLetters.InsertionId insertionId = EventDeadLetters.InsertionId.of(insertionUuid);
+        MailboxListener.MailboxAdded event = EventFactory.mailboxAdded()
+            .eventId(Event.EventId.of(uuid))
+            .user(User.fromUsername(USERNAME))
+            .sessionId(MailboxSession.SessionId.of(452))
+            .mailboxId(InMemoryId.of(453))
+            .mailboxPath(MailboxPath.forUser(USERNAME, "Important-mailbox"))
+            .build();
+
+        guiceJamesServer
+            .getProbe(EventDeadLettersProbe.class)
+            .getEventDeadLetters()
+            .store(group, event, insertionId)
+            .block();
+
+        String taskId = with()
+            .queryParam("action", "reDeliver")
+        .post("/events/deadLetter/groups/" + group.asString())
+        .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("failed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(EventDeadLettersRedeliverTask.TYPE.asString()));
+    }
+
+    @Test
+    public void postRedeliverSingleEventShouldCreateATask() {
+        String uuid = "6e0dd59d-660e-4d9b-b22f-0354479f47b4";
+        String insertionUuid = "6e0dd59d-660e-4d9b-b22f-0354479f47b7";
+        Group group = new GenericGroup("a");
+        EventDeadLetters.InsertionId insertionId = EventDeadLetters.InsertionId.of(insertionUuid);
+        MailboxListener.MailboxAdded event = EventFactory.mailboxAdded()
+            .eventId(Event.EventId.of(uuid))
+            .user(User.fromUsername(USERNAME))
+            .sessionId(MailboxSession.SessionId.of(452))
+            .mailboxId(InMemoryId.of(453))
+            .mailboxPath(MailboxPath.forUser(USERNAME, "Important-mailbox"))
+            .build();
+
+        guiceJamesServer
+            .getProbe(EventDeadLettersProbe.class)
+            .getEventDeadLetters()
+            .store(group, event, insertionId)
+            .block();
+
+        String taskId = with()
+            .queryParam("action", "reDeliver")
+        .post("/events/deadLetter/groups/" + group.asString() + "/" + insertionUuid)
+        .then()
+            .statusCode(HttpStatus.CREATED_201)
+            .extract()
+            .jsonPath()
+            .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("failed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(EventDeadLettersRedeliverTask.TYPE.asString()));
+    }
+
+    @Test
+    public void clearMailQueueShouldCompleteWhenNoQueryParameters() {
+        String firstMailQueue = with()
+                .basePath(MailQueueRoutes.BASE_URL)
+            .get()
+            .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .extract()
+                .body()
+                .jsonPath()
+                .getString("[0]");
+
+        String taskId = with()
+                .basePath(MailQueueRoutes.BASE_URL)
+            .delete(firstMailQueue + "/mails")
+                .jsonPath()
+                .getString("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(ClearMailQueueTask.TYPE.asString()));
+    }
+
+    @Test
+    public void blobStoreBasedGarbageCollectionShoudComplete() {
+        String taskId =
+            with()
+                .basePath(DeletedMessagesVaultRoutes.ROOT_PATH)
+                .queryParam("scope", "expired")
+            .delete()
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(taskId))
+            .body("type", is("deletedMessages/blobStoreBasedGarbageCollection"));
+    }
+
+    @Test
+    public void clearMailRepositoryShouldComplete() {
+        String escapedRepositoryPath = with()
+                .basePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
+            .get()
+            .then()
+                .statusCode(HttpStatus.OK_200)
+                .contentType(ContentType.JSON)
+                .extract()
+                .body()
+                .jsonPath()
+                .getString("[0].path");
+
+        String taskId = with()
+                .basePath(MailRepositoriesRoutes.MAIL_REPOSITORIES)
+            .delete(escapedRepositoryPath + "/mails")
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(taskId))
+            .body("type", is(ClearMailRepositoryTask.TYPE.asString()));
+    }
+
+
+    @Test
+    public void mailboxMergingShouldComplete() {
+        MailboxId origin = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
+        MailboxId destination = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX + "2");
+
+        String taskId = given()
+                .body("{" +
+                    "    \"mergeOrigin\":\"" + origin.serialize() + "\"," +
+                    "    \"mergeDestination\":\"" + destination.serialize() + "\"" +
+                    "}")
+            .post(CassandraMailboxMergingRoutes.BASE)
+                .jsonPath()
+                .getString("taskId");
+
+        with()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is(TaskManager.Status.COMPLETED.getValue()))
+            .body("taskId", is(taskId))
+            .body("type", is(MailboxMergingTask.MAILBOX_MERGING.asString()));
+    }
+
+    @Test
+    public void singleMailboxReindexingShouldComplete() {
+        MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
+
+        String taskId = when()
+            .post("/mailboxes/" + mailboxId.serialize() + "?task=reIndex")
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(Matchers.notNullValue()))
+            .body("type", is(SingleMailboxReindexingTask.MAILBOX_RE_INDEXING.asString()));
+    }
+
+    @Test
+    public void deletedMessagesVaultDeleteShouldCompleteEvenNoDeletedMessageExisted() throws Exception {
+        dataProbe.addUser(USERNAME, "password");
+        mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
+        ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
+            USERNAME,
+            MailboxPath.forUser(USERNAME, MailboxConstants.INBOX),
+            new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
+            new Date(),
+            false,
+            new Flags());
+
+        String taskId =
+            with()
+                .basePath(DeletedMessagesVaultRoutes.ROOT_PATH)
+            .delete(USERS + SEPARATOR + USERNAME + SEPARATOR + MESSAGE_PATH_PARAM + SEPARATOR + composedMessageId.getMessageId().serialize())
+                .jsonPath()
+                .get("taskId");
+
+        given()
+            .basePath(TasksRoutes.BASE)
+        .when()
+            .get(taskId + "/await")
+        .then()
+            .body("status", is("completed"))
+            .body("taskId", is(taskId))
+            .body("type", is(DeletedMessagesVaultDeleteTask.TYPE.asString()));
+    }
+}
\ No newline at end of file
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTask.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTask.java
index c689bb9..bb5f4e6 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTask.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultDeleteTask.java
@@ -34,7 +34,7 @@ import reactor.core.publisher.Mono;
 
 public class DeletedMessagesVaultDeleteTask implements Task {
 
-    static final TaskType TYPE = TaskType.of("deletedMessages/delete");
+    public static final TaskType TYPE = TaskType.of("deletedMessages/delete");
 
     public static class Factory {
 
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTask.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTask.java
index d90daee..4813f62 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTask.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultExportTask.java
@@ -35,9 +35,9 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 
-class DeletedMessagesVaultExportTask implements Task {
+public class DeletedMessagesVaultExportTask implements Task {
 
-    static final TaskType TYPE = TaskType.of("deletedMessages/export");
+    public static final TaskType TYPE = TaskType.of("deletedMessages/export");
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
 
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTask.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTask.java
index 6ea283d..a5915c5 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTask.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRestoreTask.java
@@ -35,9 +35,9 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.VisibleForTesting;
 
-class DeletedMessagesVaultRestoreTask implements Task {
+public class DeletedMessagesVaultRestoreTask implements Task {
 
-    static final TaskType TYPE = TaskType.of("deletedMessages/restore");
+    public static final TaskType TYPE = TaskType.of("deletedMessages/restore");
 
     public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation {
         private final User user;
diff --git a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutes.java b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutes.java
index a94b161..b557261 100644
--- a/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutes.java
+++ b/server/protocols/webadmin/webadmin-mailbox-deleted-message-vault/src/main/java/org/apache/james/webadmin/vault/routes/DeletedMessagesVaultRoutes.java
@@ -139,8 +139,8 @@ public class DeletedMessagesVaultRoutes implements Routes {
 
     public static final String ROOT_PATH = "deletedMessages";
     public static final String USERS = "users";
+    public static final String MESSAGE_PATH_PARAM = "messages";
     private static final String USER_PATH_PARAM = ":user";
-    static final String MESSAGE_PATH_PARAM = "messages";
     private static final String MESSAGE_ID_PARAM = ":messageId";
     static final String USER_PATH = ROOT_PATH + SEPARATOR + USERS + SEPARATOR + USER_PATH_PARAM;
     private static final String DELETE_PATH = ROOT_PATH + SEPARATOR + USERS + SEPARATOR + USER_PATH_PARAM + SEPARATOR + MESSAGE_PATH_PARAM + SEPARATOR + MESSAGE_ID_PARAM;


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