blob: cd130fe3272ef9578ef1fdbff282172adfdfb83f [file] [log] [blame]
/****************************************************************
* 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.rabbitmq;
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.empty;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.stream.Stream;
import javax.mail.Flags;
import org.apache.james.CassandraExtension;
import org.apache.james.CassandraRabbitMQJamesConfiguration;
import org.apache.james.CassandraRabbitMQJamesServerMain;
import org.apache.james.DockerElasticSearchExtension;
import org.apache.james.GuiceJamesServer;
import org.apache.james.JamesServerBuilder;
import org.apache.james.JamesServerExtension;
import org.apache.james.SearchConfiguration;
import org.apache.james.backends.cassandra.versions.CassandraSchemaVersionManager;
import org.apache.james.backends.cassandra.versions.SchemaVersion;
import org.apache.james.core.Username;
import org.apache.james.core.builder.MimeMessageBuilder;
import org.apache.james.junit.categories.BasicFeature;
import org.apache.james.mailbox.MailboxSession;
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.AwsS3BlobStoreExtension;
import org.apache.james.modules.EventDeadLettersProbe;
import org.apache.james.modules.MailboxProbeImpl;
import org.apache.james.modules.RabbitMQExtension;
import org.apache.james.modules.blobstore.BlobStoreConfiguration;
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.integration.WebadminIntegrationTestModule;
import org.apache.james.webadmin.routes.CassandraMailboxMergingRoutes;
import org.apache.james.webadmin.routes.CassandraMappingsRoutes;
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.vault.routes.DeletedMessagesVaultRoutes;
import org.apache.mailet.base.test.FakeMail;
import org.eclipse.jetty.http.HttpStatus;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
@Tag(BasicFeature.TAG)
class RabbitMQWebAdminServerTaskSerializationIntegrationTest {
@RegisterExtension
static JamesServerExtension testExtension = new JamesServerBuilder<CassandraRabbitMQJamesConfiguration>(tmpDir ->
CassandraRabbitMQJamesConfiguration.builder()
.workingDirectory(tmpDir)
.configurationFromClasspath()
.blobStore(BlobStoreConfiguration.builder()
.s3()
.disableCache()
.deduplication())
.searchConfiguration(SearchConfiguration.elasticSearch())
.build())
.extension(new DockerElasticSearchExtension())
.extension(new CassandraExtension())
.extension(new AwsS3BlobStoreExtension())
.extension(new RabbitMQExtension())
.server(configuration -> CassandraRabbitMQJamesServerMain.createServer(configuration)
.overrideWith(new WebadminIntegrationTestModule()))
.build();
private static final String DOMAIN = "domain";
private static final String USERNAME = "username@" + DOMAIN;
private DataProbe dataProbe;
private MailboxProbe mailboxProbe;
@BeforeEach
void setUp(GuiceJamesServer guiceJamesServer) throws Exception {
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();
}
@Test
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("full-reindexing"))
.body("additionalInformation.successfullyReprocessedMailCount", is(0))
.body("additionalInformation.failedReprocessedMailCount", is(0))
.body("additionalInformation.messageFailures", is(anEmptyMap()));
}
@Test
void recomputeFastViewProjectionItemsShouldComplete(GuiceJamesServer server) throws Exception {
server.getProbe(DataProbeImpl.class).addUser(USERNAME, "secret");
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
mailboxProbe.appendMessage(
USERNAME,
MailboxPath.inbox(Username.of(USERNAME)),
new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
new Date(),
false,
new Flags());
String taskId = with()
.post("/mailboxes?task=recomputeFastViewProjectionItems")
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(notNullValue()))
.body("type", is("RecomputeAllFastViewProjectionItemsTask"))
.body("additionalInformation.processedMessageCount", is(1))
.body("additionalInformation.failedMessageCount", is(0));
}
@Test
void populateEmailQueryViewShouldComplete(GuiceJamesServer server) throws Exception {
server.getProbe(DataProbeImpl.class).addUser(USERNAME, "secret");
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
mailboxProbe.appendMessage(
USERNAME,
MailboxPath.inbox(Username.of(USERNAME)),
new ByteArrayInputStream("Subject: test\r\n\r\ntestmail".getBytes()),
new Date(),
false,
new Flags());
String taskId = with()
.post("/mailboxes?task=populateEmailQueryView")
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(notNullValue()))
.body("type", is("PopulateEmailQueryViewTask"))
.body("additionalInformation.processedMessageCount", is(1))
.body("additionalInformation.failedMessageCount", is(0));
}
@Test
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("delete-mails-from-mail-queue"))
.body("additionalInformation.mailQueueName", is(notNullValue()))
.body("additionalInformation.remainingCount", is(0))
.body("additionalInformation.initialCount", is(0))
.body("additionalInformation.sender", is(USERNAME))
.body("additionalInformation.name", is(nullValue()))
.body("additionalInformation.recipient", is(nullValue()))
;
}
@Test
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("reprocessing-all"))
.body("additionalInformation.repositoryPath", is(notNullValue()))
.body("additionalInformation.targetQueue", is(notNullValue()))
.body("additionalInformation.targetProcessor", is(nullValue()))
.body("additionalInformation.initialCount", is(0))
.body("additionalInformation.remainingCount", is(0));
}
@Test
void reprocessingOneMailShouldCreateATask(GuiceJamesServer guiceJamesServer) 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();
String mailKey = "name1";
repository.store(FakeMail.builder()
.name(mailKey)
.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("reprocessing-one"))
.body("additionalInformation.repositoryPath", is(mailRepositoryUrl.asString()))
.body("additionalInformation.targetQueue", is(notNullValue()))
.body("additionalInformation.mailKey", is(mailKey))
.body("additionalInformation.targetProcessor", is(nullValue()));
}
@Test
void singleMessageReindexingShouldCompleteWhenMail() throws Exception {
MailboxId mailboxId = mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
USERNAME,
MailboxPath.inbox(Username.of(USERNAME)),
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("message-reindexing"))
.body("additionalInformation.mailboxId", is(mailboxId.serialize()))
.body("additionalInformation.uid", is(Math.toIntExact(composedMessageId.getUid().asLong())));
}
@Test
void messageIdReIndexingShouldCompleteWhenMail() throws Exception {
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
USERNAME,
MailboxPath.inbox(Username.of(USERNAME)),
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("messageId-reindexing"))
.body("additionalInformation.messageId", is(composedMessageId.getMessageId().serialize()));
}
@Test
void userReindexingShouldComplete() {
String taskId = with()
.queryParam("task", "reIndex")
.post("users/" + USERNAME + "/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("user-reindexing"))
.body("additionalInformation.successfullyReprocessedMailCount", is(0))
.body("additionalInformation.failedReprocessedMailCount", is(0))
.body("additionalInformation.username", is(USERNAME))
.body("additionalInformation.messageFailures", is(anEmptyMap()));
}
@Test
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("deleted-messages-restore"))
.body("additionalInformation.username", is(USERNAME))
.body("additionalInformation.successfulRestoreCount", is(0))
.body("additionalInformation.errorRestoreCount", is(0));
}
@Test
void deletedMessageVaultExportShouldComplete() throws Exception {
dataProbe.addUser(USERNAME, "password");
String query = "{" +
"\"combinator\": \"and\"," +
"\"criteria\": []" +
"}";
String exportTo = "exportTo@james.org";
String taskId = with()
.basePath(DeletedMessagesVaultRoutes.ROOT_PATH)
.queryParam("action", "export")
.queryParam("exportTo", exportTo)
.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("deleted-messages-export"))
.body("additionalInformation.userExportFrom", is(USERNAME))
.body("additionalInformation.exportTo", is(exportTo))
.body("additionalInformation.totalExportedMessages", is(0));
}
@Test
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("error-recovery-indexation"))
.body("additionalInformation.successfullyReprocessedMailCount", is(0))
.body("additionalInformation.failedReprocessedMailCount", is(0))
.body("additionalInformation.messageFailures", is(anEmptyMap()));
}
@Test
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("event-dead-letters-redeliver-all"))
.body("additionalInformation.successfulRedeliveriesCount", is(0))
.body("additionalInformation.failedRedeliveriesCount", is(0));
}
@Test
void eventDeadLettersRedeliverShouldCreateATask(GuiceJamesServer guiceJamesServer) {
Group group = new GenericGroup("a");
MailboxListener.MailboxAdded event = createMailboxAdded();
guiceJamesServer
.getProbe(EventDeadLettersProbe.class)
.getEventDeadLetters()
.store(group, event)
.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("event-dead-letters-redeliver-group"))
.body("additionalInformation.successfulRedeliveriesCount", is(0))
.body("additionalInformation.failedRedeliveriesCount", is(0))
.body("additionalInformation.group", is(group.asString()));
}
@Test
void postRedeliverSingleEventShouldCreateATask(GuiceJamesServer guiceJamesServer) {
Group group = new GenericGroup("a");
MailboxListener.MailboxAdded event = createMailboxAdded();
EventDeadLetters.InsertionId insertionId = guiceJamesServer
.getProbe(EventDeadLettersProbe.class)
.getEventDeadLetters()
.store(group, event)
.block();
String taskId = with()
.queryParam("action", "reDeliver")
.post("/events/deadLetter/groups/" + group.asString() + "/" + insertionId.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("event-dead-letters-redeliver-one"))
.body("additionalInformation.successfulRedeliveriesCount", is(0))
.body("additionalInformation.failedRedeliveriesCount", is(0))
.body("additionalInformation.group", is(group.asString()))
.body("additionalInformation.insertionId", is(insertionId.asString()));
}
@Test
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("clear-mail-queue"))
.body("additionalInformation.mailQueueName", is(notNullValue()))
.body("additionalInformation.initialCount", is(0))
.body("additionalInformation.remainingCount", is(0));
}
@Test
void blobStoreVaultGarbageCollectionShouldComplete() {
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("deleted-messages-blob-store-based-garbage-collection"))
.body("additionalInformation.beginningOfRetentionPeriod", is(notNullValue()))
.body("additionalInformation.deletedBuckets", is(empty()));
}
@Test
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("clear-mail-repository"))
.body("additionalInformation.repositoryPath", is(notNullValue()))
.body("additionalInformation.initialCount", is(0))
.body("additionalInformation.remainingCount", is(0));
}
@Test
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("mailbox-merging"))
.body("additionalInformation.oldMailboxId", is(origin.serialize()))
.body("additionalInformation.newMailboxId", is(destination.serialize()))
.body("additionalInformation.totalMessageCount", is(0))
.body("additionalInformation.messageMovedCount", is(0))
.body("additionalInformation.messageFailedCount", is(0));
}
@Test
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("mailbox-reindexing"))
.body("additionalInformation.successfullyReprocessedMailCount", is(0))
.body("additionalInformation.failedReprocessedMailCount", is(0))
.body("additionalInformation.mailboxId", is(mailboxId.serialize()))
.body("additionalInformation.messageFailures", is(anEmptyMap()));
}
@Test
void deletedMessagesVaultDeleteShouldCompleteEvenNoDeletedMessageExisted() throws Exception {
dataProbe.addUser(USERNAME, "password");
mailboxProbe.createMailbox(MailboxConstants.USER_NAMESPACE, USERNAME, MailboxConstants.INBOX);
ComposedMessageId composedMessageId = mailboxProbe.appendMessage(
USERNAME,
MailboxPath.inbox(Username.of(USERNAME)),
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("deleted-messages-delete"))
.body("additionalInformation.username", is(USERNAME))
.body("additionalInformation.deleteMessageId", is(composedMessageId.getMessageId().serialize()));
}
@Test
void cassandraMigrationShouldComplete() {
SchemaVersion toVersion = CassandraSchemaVersionManager.MAX_VERSION;
String taskId = with()
.body(String.valueOf(toVersion.getValue()))
.post("cassandra/version/upgrade")
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(taskId))
.body("type", is("cassandra-migration"))
.body("additionalInformation.toVersion", is(toVersion.getValue()));
}
@Test
void cassandraMappingsSolveInconsistenciesShouldComplete() {
String taskId = with()
.basePath(CassandraMappingsRoutes.ROOT_PATH)
.queryParam("action", "SolveInconsistencies")
.post()
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(taskId))
.body("type", is("cassandra-mappings-solve-inconsistencies"))
.body("additionalInformation.successfulMappingsCount", is(0))
.body("additionalInformation.errorMappingsCount", is(0));
}
@Test
void recomputeMailboxCountersShouldComplete() {
String taskId = with()
.basePath("/mailboxes")
.queryParam("task", "RecomputeMailboxCounters")
.post()
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(taskId))
.body("type", is("recompute-mailbox-counters"))
.body("additionalInformation.processedMailboxes", is(0));
}
@Test
void recomputeCurrentQuotasShouldComplete() {
String taskId = with()
.basePath("/quota/users")
.queryParam("task", "RecomputeCurrentQuotas")
.post()
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(taskId))
.body("type", is("recompute-current-quotas"))
.body("additionalInformation.processedQuotaRoots", is(0))
.body("additionalInformation.failedQuotaRoots", empty());
}
private MailboxListener.MailboxAdded createMailboxAdded() {
String uuid = "6e0dd59d-660e-4d9b-b22f-0354479f47b4";
return EventFactory.mailboxAdded()
.eventId(Event.EventId.of(uuid))
.user(Username.of(USERNAME))
.sessionId(MailboxSession.SessionId.of(452))
.mailboxId(InMemoryId.of(453))
.mailboxPath(MailboxPath.forUser(Username.of(USERNAME), "Important-mailbox"))
.build();
}
@Test
void republishNotProcessedMailsOnSpoolShouldComplete() {
String taskId = with()
.basePath("/mailQueues/spool")
.queryParam("action", "RepublishNotProcessedMails")
.queryParam("olderThan", "2d")
.post()
.jsonPath()
.get("taskId");
given()
.basePath(TasksRoutes.BASE)
.when()
.get(taskId + "/await")
.then()
.body("status", is("completed"))
.body("taskId", is(taskId))
.body("type", is("republish-not-processed-mails"))
.body("additionalInformation.nbRequeuedMails", is(0));
}
}