james-server-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From btell...@apache.org
Subject [03/12] james-project git commit: JAMES-2555 Implementing re-indexing routes
Date Tue, 23 Oct 2018 01:44:34 GMT
JAMES-2555 Implementing re-indexing routes

This allows re-indexing globally, per-user, per-mailbox and per-message


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

Branch: refs/heads/master
Commit: a68dae1c14fbe0b8740e0ac183b392f6936d741c
Parents: 05b38b4
Author: Benoit Tellier <btellier@linagora.com>
Authored: Fri Oct 12 11:31:03 2018 +0700
Committer: Benoit Tellier <btellier@linagora.com>
Committed: Tue Oct 23 08:43:21 2018 +0700

----------------------------------------------------------------------
 .../tools/indexer/ReIndexerPerformer.java       |   8 +-
 .../protocols/webadmin/webadmin-mailbox/pom.xml |   5 +
 .../james/webadmin/routes/ReindexingRoutes.java | 179 +++++
 .../webadmin/routes/ReindexingRoutesTest.java   | 719 +++++++++++++++++++
 4 files changed, 907 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/james-project/blob/a68dae1c/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
----------------------------------------------------------------------
diff --git a/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
b/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
index 625adda..92de5be 100644
--- a/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
+++ b/mailbox/tools/indexer/src/main/java/org/apache/mailbox/tools/indexer/ReIndexerPerformer.java
@@ -49,7 +49,7 @@ import org.slf4j.LoggerFactory;
 import com.github.fge.lambdas.Throwing;
 import com.google.common.collect.ImmutableList;
 
-class ReIndexerPerformer {
+public class ReIndexerPerformer {
     private static final Logger LOGGER = LoggerFactory.getLogger(ReIndexerPerformer.class);
 
     private static final int NO_LIMIT = 0;
@@ -60,9 +60,9 @@ class ReIndexerPerformer {
     private final MailboxSessionMapperFactory mailboxSessionMapperFactory;
 
     @Inject
-    ReIndexerPerformer(MailboxManager mailboxManager,
-                       ListeningMessageSearchIndex messageSearchIndex,
-                       MailboxSessionMapperFactory mailboxSessionMapperFactory) {
+    public ReIndexerPerformer(MailboxManager mailboxManager,
+                              ListeningMessageSearchIndex messageSearchIndex,
+                              MailboxSessionMapperFactory mailboxSessionMapperFactory) {
         this.mailboxManager = mailboxManager;
         this.messageSearchIndex = messageSearchIndex;
         this.mailboxSessionMapperFactory = mailboxSessionMapperFactory;

http://git-wip-us.apache.org/repos/asf/james-project/blob/a68dae1c/server/protocols/webadmin/webadmin-mailbox/pom.xml
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/pom.xml b/server/protocols/webadmin/webadmin-mailbox/pom.xml
index 8499f92..60782d7 100644
--- a/server/protocols/webadmin/webadmin-mailbox/pom.xml
+++ b/server/protocols/webadmin/webadmin-mailbox/pom.xml
@@ -61,6 +61,11 @@
         </dependency>
         <dependency>
             <groupId>${james.groupId}</groupId>
+            <artifactId>apache-james-mailbox-tools-indexer</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>${james.groupId}</groupId>
             <artifactId>apache-james-mailbox-quota-search</artifactId>
         </dependency>
         <dependency>

http://git-wip-us.apache.org/repos/asf/james-project/blob/a68dae1c/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/ReindexingRoutes.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/ReindexingRoutes.java
b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/ReindexingRoutes.java
new file mode 100644
index 0000000..512ef57
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/ReindexingRoutes.java
@@ -0,0 +1,179 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.webadmin.routes;
+
+import javax.inject.Inject;
+
+import org.apache.james.core.User;
+import org.apache.james.mailbox.MailboxManager;
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageUid;
+import org.apache.james.mailbox.exception.MailboxException;
+import org.apache.james.mailbox.exception.MailboxNotFoundException;
+import org.apache.james.mailbox.indexer.ReIndexer;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.task.Task;
+import org.apache.james.task.TaskId;
+import org.apache.james.task.TaskManager;
+import org.apache.james.webadmin.Routes;
+import org.apache.james.webadmin.dto.TaskIdDto;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.eclipse.jetty.http.HttpStatus;
+
+import com.github.fge.lambdas.supplier.ThrowingSupplier;
+
+import spark.Request;
+import spark.Response;
+import spark.Service;
+
+public class ReindexingRoutes implements Routes {
+    private static final String BASE_PATH = "/mailboxIndex";
+    private static final String USER_PARAM = ":user";
+    private static final String MAILBOX_PARAM = ":mailbox";
+    private static final String UID_PARAM = ":uid";
+    private static final String USER_PATH = BASE_PATH + "/users/" + USER_PARAM;
+    private static final String MAILBOX_PATH = USER_PATH + "/mailboxes/" + MAILBOX_PARAM;
+    private static final String MESSAGE_PATH = MAILBOX_PATH + "/mails/" + UID_PARAM;
+
+    private final TaskManager taskManager;
+    private final MailboxManager mailboxManager;
+    private final MailboxId.Factory mailboxIdFactory;
+    private final ReIndexer reIndexer;
+    private final JsonTransformer jsonTransformer;
+
+    @Inject
+    public ReindexingRoutes(TaskManager taskManager, MailboxManager mailboxManager, MailboxId.Factory
mailboxIdFactory, ReIndexer reIndexer, JsonTransformer jsonTransformer) {
+        this.taskManager = taskManager;
+        this.mailboxManager = mailboxManager;
+        this.mailboxIdFactory = mailboxIdFactory;
+        this.reIndexer = reIndexer;
+        this.jsonTransformer = jsonTransformer;
+    }
+
+    @Override
+    public String getBasePath() {
+        return BASE_PATH;
+    }
+
+    @Override
+    public void define(Service service) {
+        service.post(BASE_PATH, this::reIndexAll, jsonTransformer);
+        service.post(USER_PATH, this::reIndexUser, jsonTransformer);
+        service.post(MAILBOX_PATH, this::reIndexMailbox, jsonTransformer);
+        service.post(MESSAGE_PATH, this::reIndexMessage, jsonTransformer);
+    }
+
+    private TaskIdDto reIndexAll(Request request, Response response) {
+        return wrap(request, response,
+            () -> reIndexer.reIndex());
+    }
+
+    private TaskIdDto reIndexUser(Request request, Response response) {
+        return wrap(request, response,
+            () -> reIndexer.reIndex(extractUser(request)));
+    }
+
+    private TaskIdDto reIndexMailbox(Request request, Response response) {
+        return wrap(request, response,
+            () -> reIndexer.reIndex(retrievePath(request)));
+    }
+
+    private TaskIdDto reIndexMessage(Request request, Response response) {
+        return wrap(request, response,
+            () -> reIndexer.reIndex(retrievePath(request), extractUid(request)));
+    }
+
+    private TaskIdDto wrap(Request request, Response response, ThrowingSupplier<Task>
taskGenerator) {
+        enforceTaskParameter(request);
+        Task task = taskGenerator.get();
+        TaskId taskId = taskManager.submit(task);
+        return TaskIdDto.respond(response, taskId);
+    }
+
+    private User extractUser(Request request) {
+        try {
+            return User.fromUsername(request.params(USER_PARAM));
+        } catch (Exception e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("Error while parsing 'user'")
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private MailboxPath retrievePath(Request request) throws MailboxException {
+        return toMailboxPath(extractUser(request), extractMailboxId(request));
+    }
+
+    private MailboxId extractMailboxId(Request request) {
+        try {
+            return mailboxIdFactory.fromString(request.params(MAILBOX_PARAM));
+        } catch (Exception e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("Error while parsing 'mailbox'")
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private MessageUid extractUid(Request request) {
+        try {
+            return MessageUid.of(Long.valueOf(request.params(UID_PARAM)));
+        } catch (NumberFormatException e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("'uid' needs to be a parsable long")
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private MailboxPath toMailboxPath(User user, MailboxId mailboxId) throws MailboxException
{
+        try {
+            MailboxSession systemSession = mailboxManager.createSystemSession(user.asString());
+            return mailboxManager.getMailbox(mailboxId, systemSession).getMailboxPath();
+        } catch (MailboxNotFoundException e) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("mailbox not found")
+                .cause(e)
+                .haltError();
+        }
+    }
+
+    private void enforceTaskParameter(Request request) {
+        String task = request.queryParams("task");
+        if (!"reIndex".equals(task)) {
+            throw ErrorResponder.builder()
+                .statusCode(HttpStatus.BAD_REQUEST_400)
+                .type(ErrorResponder.ErrorType.INVALID_ARGUMENT)
+                .message("task query parameter is mandatory. The only supported value is
`reIndex`")
+                .haltError();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/james-project/blob/a68dae1c/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ReindexingRoutesTest.java
----------------------------------------------------------------------
diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ReindexingRoutesTest.java
b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ReindexingRoutesTest.java
new file mode 100644
index 0000000..dd20ca6
--- /dev/null
+++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/ReindexingRoutesTest.java
@@ -0,0 +1,719 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.webadmin.routes;
+
+import static io.restassured.RestAssured.given;
+import static io.restassured.RestAssured.when;
+import static io.restassured.RestAssured.with;
+import static org.apache.james.webadmin.WebAdminServer.NO_CONFIGURATION;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import org.apache.james.mailbox.MailboxSession;
+import org.apache.james.mailbox.MessageManager;
+import org.apache.james.mailbox.acl.SimpleGroupMembershipResolver;
+import org.apache.james.mailbox.indexer.ReIndexer;
+import org.apache.james.mailbox.inmemory.InMemoryId;
+import org.apache.james.mailbox.inmemory.InMemoryMailboxManager;
+import org.apache.james.mailbox.inmemory.manager.InMemoryIntegrationResources;
+import org.apache.james.mailbox.model.ComposedMessageId;
+import org.apache.james.mailbox.model.MailboxId;
+import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.mailbox.store.mail.model.Mailbox;
+import org.apache.james.mailbox.store.mail.model.MailboxMessage;
+import org.apache.james.mailbox.store.search.ListeningMessageSearchIndex;
+import org.apache.james.metrics.logger.DefaultMetricFactory;
+import org.apache.james.task.MemoryTaskManager;
+import org.apache.james.webadmin.WebAdminServer;
+import org.apache.james.webadmin.WebAdminUtils;
+import org.apache.james.webadmin.utils.ErrorResponder;
+import org.apache.james.webadmin.utils.JsonTransformer;
+import org.apache.mailbox.tools.indexer.FullReindexingTask;
+import org.apache.mailbox.tools.indexer.ReIndexerImpl;
+import org.apache.mailbox.tools.indexer.ReIndexerPerformer;
+import org.apache.mailbox.tools.indexer.SingleMailboxReindexingTask;
+import org.apache.mailbox.tools.indexer.SingleMessageReindexingTask;
+import org.apache.mailbox.tools.indexer.UserReindexingTask;
+import org.eclipse.jetty.http.HttpStatus;
+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 org.mockito.ArgumentCaptor;
+
+import io.restassured.RestAssured;
+
+class ReindexingRoutesTest {
+    private static final String USERNAME = "benwa@apache.org";
+    private static final MailboxPath INBOX = MailboxPath.forUser(USERNAME, "INBOX");
+
+    private WebAdminServer webAdminServer;
+    private ListeningMessageSearchIndex searchIndex;
+    private InMemoryMailboxManager mailboxManager;
+
+    @BeforeEach
+    void beforeEach() throws Exception {
+        mailboxManager = new InMemoryIntegrationResources().createMailboxManager(new SimpleGroupMembershipResolver());
+        MemoryTaskManager taskManager = new MemoryTaskManager();
+        InMemoryId.Factory mailboxIdFactory = new InMemoryId.Factory();
+        searchIndex = mock(ListeningMessageSearchIndex.class);
+        ReIndexer reIndexer = new ReIndexerImpl(
+            new ReIndexerPerformer(
+                mailboxManager,
+                searchIndex,
+                mailboxManager.getMapperFactory()));
+        JsonTransformer jsonTransformer = new JsonTransformer();
+
+        webAdminServer = WebAdminUtils.createWebAdminServer(
+            new DefaultMetricFactory(),
+            new TasksRoutes(taskManager, jsonTransformer),
+            new ReindexingRoutes(
+                taskManager,
+                mailboxManager,
+                mailboxIdFactory,
+                reIndexer,
+                jsonTransformer));
+        webAdminServer.configure(NO_CONFIGURATION);
+        webAdminServer.await();
+
+        RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer).build();
+        RestAssured.enableLoggingOfRequestAndResponseIfValidationFails();
+    }
+
+    @AfterEach
+    void tearDown() {
+        webAdminServer.destroy();
+    }
+
+    @Nested
+    class FullReprocessing {
+        @Nested
+        class Validation {
+            @Test
+            void fullReprocessingShouldFailWithNoTask() {
+                when()
+                    .post("/mailboxIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void fullReprocessingShouldFailWithBadTask() {
+                when()
+                    .post("/mailboxIndex?task=bad")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+        }
+
+        @Nested
+        class TaskDetails {
+            @Test
+            void fullReprocessingShouldNotFailWhenNoMail() {
+                String taskId = with()
+                    .post("/mailboxIndex?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))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(0))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+
+            @Test
+            void fullReprocessingShouldReturnTaskDetailsWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                mailboxManager.createMailbox(INBOX, systemSession).get();
+                mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = with()
+                    .post("/mailboxIndex?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))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(1))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+        }
+
+        @Nested
+        class SideEffects {
+            @Test
+            void fullReprocessingShouldPerformReprocessingWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                ComposedMessageId createdMessage = mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = with()
+                    .post("/mailboxIndex?task=reIndex")
+                    .jsonPath()
+                    .get("taskId");
+
+                with()
+                    .basePath(TasksRoutes.BASE)
+                    .get(taskId + "/await")
+                    .then()
+                    .body("status", is("completed"));
+
+
+                ArgumentCaptor<MailboxMessage> messageCaptor = ArgumentCaptor.forClass(MailboxMessage.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor1 = ArgumentCaptor.forClass(Mailbox.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor2 = ArgumentCaptor.forClass(Mailbox.class);
+
+                verify(searchIndex).deleteAll(any(MailboxSession.class), mailboxCaptor1.capture());
+                verify(searchIndex).add(any(MailboxSession.class), mailboxCaptor2.capture(),
messageCaptor.capture());
+                verifyNoMoreInteractions(searchIndex);
+
+                assertThat(mailboxCaptor1.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(mailboxCaptor2.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(messageCaptor.getValue()).matches(message -> message.getMailboxId().equals(mailboxId)
+                    && message.getUid().equals(createdMessage.getUid()));
+            }
+        }
+    }
+
+    @Nested
+    class UserReprocessing {
+        @Nested
+        class Validation {
+            @Test
+            void userReprocessingShouldFailWithNoTask() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME)
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void userReprocessingShouldFailWithBadTask() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "?task=bad")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void userReprocessingShouldFailWithBadUser() {
+                when()
+                    .post("/mailboxIndex/users/bad@bad@bad?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("Error while parsing 'user'"));
+            }
+        }
+
+        @Nested
+        class TaskDetails {
+            @Test
+            void userReprocessingShouldNotFailWhenNoMail() {
+                String taskId = with()
+                    .post("/mailboxIndex/users/" + USERNAME + "?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(UserReindexingTask.USER_RE_INDEXING))
+                    .body("additionalInformation.user", is("benwa@apache.org"))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(0))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+
+            @Test
+            void userReprocessingShouldReturnTaskDetailsWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                mailboxManager.createMailbox(INBOX, systemSession).get();
+                mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = with()
+                    .post("/mailboxIndex/users/" + USERNAME + "?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(UserReindexingTask.USER_RE_INDEXING))
+                    .body("additionalInformation.user", is("benwa@apache.org"))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(1))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+        }
+
+        @Nested
+        class SideEffects {
+            @Test
+            void userReprocessingShouldPerformReprocessingWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                ComposedMessageId createdMessage = mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = with()
+                    .post("/mailboxIndex/users/" + USERNAME + "?task=reIndex")
+                    .jsonPath()
+                    .get("taskId");
+
+                given()
+                    .basePath(TasksRoutes.BASE)
+                .when()
+                    .get(taskId + "/await")
+                .then()
+                    .body("status", is("completed"));
+
+
+                ArgumentCaptor<MailboxMessage> messageCaptor = ArgumentCaptor.forClass(MailboxMessage.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor1 = ArgumentCaptor.forClass(Mailbox.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor2 = ArgumentCaptor.forClass(Mailbox.class);
+
+                verify(searchIndex).deleteAll(any(MailboxSession.class), mailboxCaptor1.capture());
+                verify(searchIndex).add(any(MailboxSession.class), mailboxCaptor2.capture(),
messageCaptor.capture());
+                verifyNoMoreInteractions(searchIndex);
+
+                assertThat(mailboxCaptor1.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(mailboxCaptor2.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(messageCaptor.getValue()).matches(message -> message.getMailboxId().equals(mailboxId)
+                    && message.getUid().equals(createdMessage.getUid()));
+            }
+        }
+    }
+
+    @Nested
+    class MailboxReprocessing {
+        @Nested
+        class Validation {
+            @Test
+            void mailboxReprocessingShouldFailWithNoTask() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize())
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void mailboxReprocessingShouldFailWithBadTask() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "?task=bad")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void mailboxReprocessingShouldFailWithBadUser() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/bad@bad@bad/mailboxes/" + mailboxId.serialize()
+ "?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("Error while parsing 'user'"));
+            }
+
+            @Test
+            void mailboxReprocessingShouldFailWithBadMailboxId() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/bad?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("Error while parsing 'mailbox'"));
+            }
+
+            @Test
+            void mailboxReprocessingShouldFailWithNonExistentMailboxId() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/36?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("mailbox not found"));
+            }
+
+            @Test
+            void mailboxReprocessingShouldFailWithNonExistentUser() {
+                when()
+                    .post("/mailboxIndex/users/notFound@domain.tld/mailboxes/36?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("mailbox not found"));
+            }
+        }
+
+        @Nested
+        class TaskDetails {
+            @Test
+            void mailboxReprocessingShouldNotFailWhenNoMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "?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(SingleMailboxReindexingTask.MAILBOX_RE_INDEXING))
+                    .body("additionalInformation.mailboxPath", is("#private:benwa@apache.org:INBOX"))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(0))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+
+            @Test
+            void mailboxReprocessingShouldReturnTaskDetailsWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "?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(SingleMailboxReindexingTask.MAILBOX_RE_INDEXING))
+                    .body("additionalInformation.mailboxPath", is("#private:benwa@apache.org:INBOX"))
+                    .body("additionalInformation.successfullyReprocessMailCount", is(1))
+                    .body("additionalInformation.failedReprocessedMailCount", is(0))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+        }
+
+        @Nested
+        class SideEffects {
+            @Test
+            void mailboxReprocessingShouldPerformReprocessingWhenMail() throws Exception
{
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                ComposedMessageId createdMessage = mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "?task=reIndex")
+                    .jsonPath()
+                    .get("taskId");
+
+                given()
+                    .basePath(TasksRoutes.BASE)
+                .when()
+                    .get(taskId + "/await")
+                .then()
+                    .body("status", is("completed"));
+
+
+                ArgumentCaptor<MailboxMessage> messageCaptor = ArgumentCaptor.forClass(MailboxMessage.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor1 = ArgumentCaptor.forClass(Mailbox.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor2 = ArgumentCaptor.forClass(Mailbox.class);
+
+                verify(searchIndex).deleteAll(any(MailboxSession.class), mailboxCaptor1.capture());
+                verify(searchIndex).add(any(MailboxSession.class), mailboxCaptor2.capture(),
messageCaptor.capture());
+                verifyNoMoreInteractions(searchIndex);
+
+                assertThat(mailboxCaptor1.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(mailboxCaptor2.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(messageCaptor.getValue()).matches(message -> message.getMailboxId().equals(mailboxId)
+                    && message.getUid().equals(createdMessage.getUid()));
+            }
+        }
+    }
+
+    @Nested
+    class MessageReprocessing {
+        @Nested
+        class Validation {
+            @Test
+            void messageReprocessingShouldFailWithNoTask() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "/mails/7")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void messageReprocessingShouldFailWithBadTask() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "/mails/7?task=bad")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("task query parameter is mandatory. The only supported
value is `reIndex`"));
+            }
+
+            @Test
+            void messageReprocessingShouldFailWithBadUser() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                when()
+                    .post("/mailboxIndex/users/bad@bad@bad/mailboxes/" + mailboxId.serialize()
+ "/mails/7?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("Error while parsing 'user'"));
+            }
+
+            @Test
+            void messageReprocessingShouldFailWithBadMailboxId() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/bad/mails/7?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("Error while parsing 'mailbox'"));
+            }
+
+            @Test
+            void messageReprocessingShouldFailWithNonExistentMailboxId() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/36/mails/7?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("mailbox not found"));
+            }
+
+            @Test
+            void messageReprocessingShouldFailWithBadUid() {
+                when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/36/mails/bad?task=reIndex")
+                .then()
+                    .statusCode(HttpStatus.BAD_REQUEST_400)
+                    .body("statusCode", is(400))
+                    .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType()))
+                    .body("message", is("mailbox not found"));
+            }
+        }
+
+        @Nested
+        class TaskDetails {
+            @Test
+            void messageReprocessingShouldNotFailWhenUidNotFound() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "/mails/1?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(SingleMessageReindexingTask.MESSAGE_RE_INDEXING))
+                    .body("additionalInformation.mailboxPath", is("#private:benwa@apache.org:INBOX"))
+                    .body("additionalInformation.uid", is(1))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+
+            @Test
+            void messageReprocessingShouldReturnTaskDetailsWhenMail() throws Exception {
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                ComposedMessageId composedMessageId = mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/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(notNullValue()))
+                    .body("type", is(SingleMessageReindexingTask.MESSAGE_RE_INDEXING))
+                    .body("additionalInformation.mailboxPath", is("#private:benwa@apache.org:INBOX"))
+                    .body("additionalInformation.uid", is((int) composedMessageId.getUid().asLong()))
+                    .body("startedDate", is(notNullValue()))
+                    .body("submitDate", is(notNullValue()))
+                    .body("completedDate", is(notNullValue()));
+            }
+        }
+
+        @Nested
+        class SideEffects {
+            @Test
+            void mailboxReprocessingShouldPerformReprocessingWhenMail() throws Exception
{
+                MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME);
+                MailboxId mailboxId = mailboxManager.createMailbox(INBOX, systemSession).get();
+                ComposedMessageId createdMessage = mailboxManager.getMailbox(INBOX, systemSession)
+                    .appendMessage(
+                        MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"),
+                        systemSession);
+
+                String taskId = when()
+                    .post("/mailboxIndex/users/" + USERNAME + "/mailboxes/" + mailboxId.serialize()
+ "/mails/"
+                        + createdMessage.getUid().asLong() + "?task=reIndex")
+                    .jsonPath()
+                    .get("taskId");
+
+                given()
+                    .basePath(TasksRoutes.BASE)
+                .when()
+                    .get(taskId + "/await")
+                .then()
+                    .body("status", is("completed"));
+
+
+                ArgumentCaptor<MailboxMessage> messageCaptor = ArgumentCaptor.forClass(MailboxMessage.class);
+                ArgumentCaptor<Mailbox> mailboxCaptor = ArgumentCaptor.forClass(Mailbox.class);
+
+                verify(searchIndex).add(any(MailboxSession.class), mailboxCaptor.capture(),
messageCaptor.capture());
+                verifyNoMoreInteractions(searchIndex);
+
+                assertThat(mailboxCaptor.getValue()).matches(mailbox -> mailbox.getMailboxId().equals(mailboxId));
+                assertThat(messageCaptor.getValue()).matches(message -> message.getMailboxId().equals(mailboxId)
+                    && message.getUid().equals(createdMessage.getUid()));
+            }
+        }
+    }
+
+}
\ No newline at end of file


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


Mime
View raw message