This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 8028baaff165bdeee35518596b3b2541f6c54d51 Author: Lan <dlkh...@linagora.com> AuthorDate: Fri Mar 6 16:06:03 2020 +0700 JAMES-3072 Add Task for Mailboxes Export Service --- .../service/MailboxesExportRequestToTask.java | 59 +++ .../webadmin/service/MailboxesExportTask.java | 118 ++++++ ...ailboxesExportTaskAdditionalInformationDTO.java | 71 ++++ .../service/MailboxesExportRequestToTaskTest.java | 442 +++++++++++++++++++++ ...oxesExportTaskAdditionalInformationDTOTest.java | 41 ++ .../MailboxesExportTaskSerializationTest.java | 45 +++ .../mailboxesExport.additionalInformation.json | 5 + .../test/resources/json/mailboxesExport.task.json | 4 + 8 files changed, 785 insertions(+) diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportRequestToTask.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportRequestToTask.java new file mode 100644 index 0000000..b0acb61 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportRequestToTask.java @@ -0,0 +1,59 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import javax.inject.Inject; + +import org.apache.james.core.Username; +import org.apache.james.task.Task; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.api.UsersRepositoryException; +import org.apache.james.webadmin.tasks.TaskFromRequestRegistry; +import org.apache.james.webadmin.tasks.TaskRegistrationKey; +import org.apache.james.webadmin.utils.ErrorResponder; +import org.eclipse.jetty.http.HttpStatus; + +import spark.Request; + +public class MailboxesExportRequestToTask extends TaskFromRequestRegistry.TaskRegistration { + + public static final TaskRegistrationKey TASK_REGISTRATION_KEY = TaskRegistrationKey.of("export"); + + @Inject + MailboxesExportRequestToTask(ExportService service, + UsersRepository usersRepository) { + + super(TASK_REGISTRATION_KEY, + request -> toTask(service, usersRepository, request)); + } + + private static Task toTask(ExportService service, UsersRepository usersRepository, Request request) throws UsersRepositoryException { + Username username = Username.of(request.params("username")); + if (usersRepository.contains(username)) { + return new MailboxesExportTask(service, username); + } + + throw ErrorResponder.builder() + .type(ErrorResponder.ErrorType.NOT_FOUND) + .statusCode(HttpStatus.NOT_FOUND_404) + .message(String.format("User '%s' does not exist", username.asString())) + .haltError(); + } +} diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTask.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTask.java new file mode 100644 index 0000000..42b0c53 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTask.java @@ -0,0 +1,118 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import java.time.Clock; +import java.time.Instant; +import java.util.Optional; + +import org.apache.james.core.Username; +import org.apache.james.json.DTOModule; +import org.apache.james.server.task.json.dto.TaskDTO; +import org.apache.james.server.task.json.dto.TaskDTOModule; +import org.apache.james.task.Task; +import org.apache.james.task.TaskExecutionDetails; +import org.apache.james.task.TaskType; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import reactor.core.scheduler.Schedulers; + +public class MailboxesExportTask implements Task { + static final TaskType TASK_TYPE = TaskType.of("MailboxesExportTask"); + + public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation { + private static AdditionalInformation from(Username username) { + return new AdditionalInformation(username, Clock.systemUTC().instant()); + } + + private final Username username; + private final Instant timestamp; + + public AdditionalInformation(Username username, Instant timestamp) { + this.username = username; + this.timestamp = timestamp; + } + + public String getUsername() { + return username.asString(); + } + + @Override + public Instant timestamp() { + return timestamp; + } + } + + public static class MailboxesExportTaskDTO implements TaskDTO { + private final String type; + private final String username; + + public MailboxesExportTaskDTO(@JsonProperty("type") String type, + @JsonProperty("username") String username) { + this.type = type; + this.username = username; + } + + @Override + public String getType() { + return type; + } + + public String getUsername() { + return username; + } + } + + public static TaskDTOModule<MailboxesExportTask, MailboxesExportTaskDTO> module(ExportService service) { + return DTOModule + .forDomainObject(MailboxesExportTask.class) + .convertToDTO(MailboxesExportTaskDTO.class) + .toDomainObjectConverter(dto -> new MailboxesExportTask(service, Username.of(dto.username))) + .toDTOConverter((task, type) -> new MailboxesExportTaskDTO(type, task.username.asString())) + .typeName(TASK_TYPE.asString()) + .withFactory(TaskDTOModule::new); + } + + private final Username username; + private final ExportService service; + + MailboxesExportTask(ExportService service, Username username) { + this.username = username; + this.service = service; + } + + @Override + public Result run() { + return service.export(username) + .subscribeOn(Schedulers.elastic()) + .block(); + } + + @Override + public TaskType type() { + return TASK_TYPE; + } + + @Override + public Optional<TaskExecutionDetails.AdditionalInformation> details() { + return Optional.of(AdditionalInformation.from(username)); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTO.java new file mode 100644 index 0000000..3050117 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTO.java @@ -0,0 +1,71 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import java.time.Instant; + +import org.apache.james.core.Username; +import org.apache.james.json.DTOModule; +import org.apache.james.server.task.json.dto.AdditionalInformationDTO; +import org.apache.james.server.task.json.dto.AdditionalInformationDTOModule; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class MailboxesExportTaskAdditionalInformationDTO implements AdditionalInformationDTO { + + public static final AdditionalInformationDTOModule<MailboxesExportTask.AdditionalInformation, MailboxesExportTaskAdditionalInformationDTO> SERIALIZATION_MODULE = + DTOModule.forDomainObject(MailboxesExportTask.AdditionalInformation.class) + .convertToDTO(MailboxesExportTaskAdditionalInformationDTO.class) + .toDomainObjectConverter(dto -> new MailboxesExportTask.AdditionalInformation( + Username.of(dto.username), + dto.timestamp)) + .toDTOConverter((details, type) -> new MailboxesExportTaskAdditionalInformationDTO( + type, + details.timestamp(), + details.getUsername())) + .typeName(MailboxesExportTask.TASK_TYPE.asString()) + .withFactory(AdditionalInformationDTOModule::new); + + private final String username; + private final Instant timestamp; + private final String type; + + private MailboxesExportTaskAdditionalInformationDTO(@JsonProperty("type") String type, + @JsonProperty("timestamp") Instant timestamp, + @JsonProperty("username") String username) { + this.type = type; + this.timestamp = timestamp; + this.username = username; + } + + @Override + public String getType() { + return type; + } + + @Override + public Instant getTimestamp() { + return timestamp; + } + + public String getUsername() { + return username; + } +} diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java new file mode 100644 index 0000000..3eb81ed --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportRequestToTaskTest.java @@ -0,0 +1,442 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import static io.restassured.RestAssured.given; +import static io.restassured.RestAssured.when; +import static io.restassured.RestAssured.with; +import static org.apache.james.mailbox.DefaultMailboxes.INBOX; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.mockito.Mockito.mock; + +import java.io.FileInputStream; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Optional; + +import org.apache.james.blob.api.BlobId; +import org.apache.james.blob.api.BlobStore; +import org.apache.james.blob.api.HashBlobId; +import org.apache.james.blob.export.api.BlobExportMechanism; +import org.apache.james.blob.export.file.FileSystemExtension; +import org.apache.james.blob.export.file.LocalFileBlobExportMechanism; +import org.apache.james.blob.memory.MemoryBlobStore; +import org.apache.james.blob.memory.MemoryDumbBlobStore; +import org.apache.james.core.Domain; +import org.apache.james.core.Username; +import org.apache.james.dnsservice.api.DNSService; +import org.apache.james.domainlist.memory.MemoryDomainList; +import org.apache.james.filesystem.api.FileSystem; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.backup.ArchiveService; +import org.apache.james.mailbox.backup.DefaultMailboxBackup; +import org.apache.james.mailbox.backup.MailArchivesLoader; +import org.apache.james.mailbox.backup.MailboxBackup; +import org.apache.james.mailbox.backup.ZipAssert; +import org.apache.james.mailbox.backup.ZipMailArchiveRestorer; +import org.apache.james.mailbox.backup.zip.ZipArchivesLoader; +import org.apache.james.mailbox.backup.zip.Zipper; +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.task.Hostname; +import org.apache.james.task.MemoryTaskManager; +import org.apache.james.task.TaskManager; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.memory.MemoryUsersRepository; +import org.apache.james.webadmin.Routes; +import org.apache.james.webadmin.WebAdminServer; +import org.apache.james.webadmin.WebAdminUtils; +import org.apache.james.webadmin.routes.TasksRoutes; +import org.apache.james.webadmin.tasks.TaskFromRequestRegistry; +import org.apache.james.webadmin.utils.ErrorResponder; +import org.apache.james.webadmin.utils.JsonTransformer; +import org.apache.mailet.base.MailAddressFixture; +import org.apache.mailet.base.test.FakeMailContext; +import org.eclipse.jetty.http.HttpStatus; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mockito; + +import io.restassured.RestAssured; +import io.restassured.filter.log.LogDetail; +import spark.Service; + +@ExtendWith(FileSystemExtension.class) +class MailboxesExportRequestToTaskTest { + + private final class ExportRoutes implements Routes { + private final ExportService service; + private final TaskManager taskManager; + private final UsersRepository usersRepository; + + private ExportRoutes(ExportService service, TaskManager taskManager, UsersRepository usersRepository) { + this.service = service; + this.taskManager = taskManager; + this.usersRepository = usersRepository; + } + + @Override + public String getBasePath() { + return BASE_PATH; + } + + @Override + public void define(Service service) { + service.post(BASE_PATH, + TaskFromRequestRegistry.builder() + .registrations(new MailboxesExportRequestToTask(this.service, usersRepository)) + .buildAsRoute(taskManager), + new JsonTransformer()); + } + } + + private static final String BASE_PATH = "users/:username/mailboxes"; + private static final String JAMES_HOST = "james-host"; + private static final Domain DOMAIN = Domain.of("domain.tld"); + private static final String CORRESPONDING_FILE_HEADER = "corresponding-file"; + private static final Username BOB = Username.fromLocalPartWithDomain("bob", DOMAIN); + private static final Username CEDRIC = Username.fromLocalPartWithDomain("cedric", DOMAIN); + private static final String PASSWORD = "password"; + private static final BlobId.Factory FACTORY = new HashBlobId.Factory(); + private static final String MESSAGE_CONTENT = "header: value\n" + + "\n" + + "body"; + + private FakeMailContext mailetContext; + private WebAdminServer webAdminServer; + private MemoryTaskManager taskManager; + private InMemoryMailboxManager mailboxManager; + private MemoryUsersRepository usersRepository; + private MailboxSession bobSession; + private BlobStore blobStore; + + @BeforeEach + void setUp(FileSystem fileSystem) throws Exception { + JsonTransformer jsonTransformer = new JsonTransformer(); + taskManager = new MemoryTaskManager(new Hostname("foo")); + + mailboxManager = InMemoryIntegrationResources.defaultResources().getMailboxManager(); + MailboxBackup backup = createMailboxBackup(); + DNSService dnsService = createDnsService(); + + usersRepository = createUsersRepository(dnsService); + + bobSession = mailboxManager.createSystemSession(BOB); + + blobStore = new MemoryBlobStore(FACTORY, new MemoryDumbBlobStore()); + mailetContext = FakeMailContext.builder().postmaster(MailAddressFixture.POSTMASTER_AT_JAMES).build(); + BlobExportMechanism blobExport = new LocalFileBlobExportMechanism(mailetContext, blobStore, fileSystem, dnsService, + LocalFileBlobExportMechanism.Configuration.DEFAULT_CONFIGURATION); + + webAdminServer = WebAdminUtils.createWebAdminServer( + new TasksRoutes(taskManager, jsonTransformer), + new ExportRoutes( + new ExportService(backup, blobStore, blobExport, usersRepository), + taskManager, usersRepository)) + .start(); + + RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer) + .setBasePath("users/" + BOB.asString() + "/mailboxes") + .log(LogDetail.URI) + .build(); + } + + private MemoryUsersRepository createUsersRepository(DNSService dnsService) throws Exception { + MemoryDomainList domainList = new MemoryDomainList(dnsService); + MemoryUsersRepository usersRepository = MemoryUsersRepository.withVirtualHosting(domainList); + + domainList.addDomain(DOMAIN); + usersRepository.addUser(BOB, PASSWORD); + return usersRepository; + } + + private DefaultMailboxBackup createMailboxBackup() { + ArchiveService archiveService = new Zipper(); + MailArchivesLoader archiveLoader = new ZipArchivesLoader(); + ZipMailArchiveRestorer archiveRestorer = new ZipMailArchiveRestorer(mailboxManager, archiveLoader); + return new DefaultMailboxBackup(mailboxManager, archiveService, archiveRestorer); + } + + private DNSService createDnsService() throws UnknownHostException { + InetAddress localHost = mock(InetAddress.class); + Mockito.when(localHost.getHostName()).thenReturn(JAMES_HOST); + DNSService dnsService = mock(DNSService.class); + Mockito.when(dnsService.getLocalHost()).thenReturn(localHost); + return dnsService; + } + + @AfterEach + void afterEach() { + webAdminServer.destroy(); + taskManager.stop(); + } + + @Test + void actionRequestParameterShouldBeCompulsory() { + when() + .post() + .then() + .statusCode(HttpStatus.BAD_REQUEST_400) + .body("statusCode", is(400)) + .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType())) + .body("message", is("Invalid arguments supplied in the user request")) + .body("details", is("'action' query parameter is compulsory. Supported values are [export]")); + } + + @Test + void exportMailboxesShouldFailUponEmptyAction() { + given() + .queryParam("action", "") + .post() + .then() + .statusCode(HttpStatus.BAD_REQUEST_400) + .body("statusCode", is(400)) + .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType())) + .body("message", is("Invalid arguments supplied in the user request")) + .body("details", is("'action' query parameter cannot be empty or blank. Supported values are [export]")); + } + + @Test + void exportMailboxesShouldFailUponInvalidAction() { + given() + .queryParam("action", "invalid") + .post() + .then() + .statusCode(HttpStatus.BAD_REQUEST_400) + .body("statusCode", is(400)) + .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType())) + .body("message", is("Invalid arguments supplied in the user request")) + .body("details", is("Invalid value supplied for query parameter 'action': invalid. Supported values are [export]")); + } + + @Test + void exportMailboxesShouldFailUponBadUsername() { + given() + .basePath("users/bad@bad@bad/mailboxes") + .queryParam("action", "export") + .post() + .then() + .statusCode(HttpStatus.BAD_REQUEST_400) + .body("statusCode", is(400)) + .body("type", is(ErrorResponder.ErrorType.INVALID_ARGUMENT.getType())) + .body("message", is("Invalid arguments supplied in the user request")) + .body("details", is("The username should not contain multiple domain delimiter.")); + } + + @Test + void exportMailboxesShouldFailUponUnknownUser() { + given() + .basePath("users/notFound/mailboxes") + .queryParam("action", "export") + .post() + .then() + .statusCode(HttpStatus.NOT_FOUND_404) + .body("statusCode", is(404)) + .body("type", is(ErrorResponder.ErrorType.NOT_FOUND.getType())) + .body("message", is("User 'notfound' does not exist")); + } + + @Test + void postShouldCreateANewTask() { + given() + .queryParam("action", "export") + .post() + .then() + .statusCode(HttpStatus.CREATED_201) + .body("taskId", notNullValue()); + } + + @Test + void exportMailboxesShouldCompleteWhenUserHasNoMailbox() { + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(taskId)) + .body("type", is("MailboxesExportTask")) + .body("additionalInformation.username", is(BOB.asString())) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + void exportMailboxesShouldProduceEmptyZipWhenUserHasNoMailbox() throws Exception { + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + String fileUrl = mailetContext.getSentMails().get(0).getMsg().getHeader(CORRESPONDING_FILE_HEADER)[0]; + ZipAssert.assertThatZip(new FileInputStream(fileUrl)) + .hasNoEntry(); + } + + @Test + void exportMailboxesShouldCompleteWhenUserHasNoMessage() throws Exception { + mailboxManager.createMailbox(MailboxPath.inbox(BOB), bobSession); + + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(taskId)) + .body("type", is("MailboxesExportTask")) + .body("additionalInformation.username", is(BOB.asString())) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + void exportMailboxesShouldProduceAZipFileWhenUserHasNoMessage() throws Exception { + mailboxManager.createMailbox(MailboxPath.inbox(BOB), bobSession); + + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await"); + + String fileUrl = mailetContext.getSentMails().get(0).getMsg().getHeader(CORRESPONDING_FILE_HEADER)[0]; + ZipAssert.assertThatZip(new FileInputStream(fileUrl)) + .containsOnlyEntriesMatching( + ZipAssert.EntryChecks.hasName(INBOX + "/").isDirectory()); + } + + @Test + void exportMailboxesShouldCompleteWhenUserHasMessage() throws Exception { + MailboxId bobInboxboxId = mailboxManager.createMailbox(MailboxPath.inbox(BOB), bobSession) + .get(); + + mailboxManager.getMailbox(bobInboxboxId, bobSession).appendMessage( + MessageManager.AppendCommand.builder().build("header: value\r\n\r\nbody"), + bobSession); + + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("status", is("completed")) + .body("taskId", is(taskId)) + .body("type", is("MailboxesExportTask")) + .body("additionalInformation.username", is(BOB.asString())) + .body("startedDate", is(notNullValue())) + .body("submitDate", is(notNullValue())) + .body("completedDate", is(notNullValue())); + } + + @Test + void exportMailboxesShouldProduceAZipFileWhenUserHasMessage() throws Exception { + MailboxId bobInboxboxId = mailboxManager.createMailbox(MailboxPath.inbox(BOB), bobSession) + .get(); + + ComposedMessageId id = mailboxManager.getMailbox(bobInboxboxId, bobSession).appendMessage( + MessageManager.AppendCommand.builder().build(MESSAGE_CONTENT), + bobSession); + + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await"); + + String fileUrl = mailetContext.getSentMails().get(0).getMsg().getHeader(CORRESPONDING_FILE_HEADER)[0]; + ZipAssert.assertThatZip(new FileInputStream(fileUrl)) + .containsOnlyEntriesMatching( + ZipAssert.EntryChecks.hasName(INBOX + "/").isDirectory(), + ZipAssert.EntryChecks.hasName(id.getMessageId().serialize()).hasStringContent(MESSAGE_CONTENT)); + } + + @Test + void exportMailboxesShouldBeUserBound() throws Exception { + MailboxId bobInboxboxId = mailboxManager.createMailbox(MailboxPath.inbox(BOB), bobSession) + .get(); + + ComposedMessageId id = mailboxManager.getMailbox(bobInboxboxId, bobSession).appendMessage( + MessageManager.AppendCommand.builder().build(MESSAGE_CONTENT), + bobSession); + + usersRepository.addUser(CEDRIC, PASSWORD); + MailboxSession cedricSession = mailboxManager.createSystemSession(CEDRIC); + Optional<MailboxId> mailboxIdCedric = mailboxManager.createMailbox(MailboxPath.inbox(CEDRIC), cedricSession); + mailboxManager.getMailbox(mailboxIdCedric.get(), cedricSession).appendMessage( + MessageManager.AppendCommand.builder().build(MESSAGE_CONTENT + CEDRIC.asString()), + cedricSession); + + String taskId = with() + .queryParam("action", "export") + .post() + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await"); + + String fileUrl = mailetContext.getSentMails().get(0).getMsg().getHeader(CORRESPONDING_FILE_HEADER)[0]; + ZipAssert.assertThatZip(new FileInputStream(fileUrl)) + .containsOnlyEntriesMatching( + ZipAssert.EntryChecks.hasName(INBOX + "/").isDirectory(), + ZipAssert.EntryChecks.hasName(id.getMessageId().serialize()).hasStringContent(MESSAGE_CONTENT)); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTOTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTOTest.java new file mode 100644 index 0000000..7102633 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskAdditionalInformationDTOTest.java @@ -0,0 +1,41 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import java.time.Instant; + +import org.apache.james.JsonSerializationVerifier; +import org.apache.james.core.Username; +import org.apache.james.util.ClassLoaderUtils; +import org.junit.jupiter.api.Test; + +class MailboxesExportTaskAdditionalInformationDTOTest { + private static final Instant INSTANT = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final MailboxesExportTask.AdditionalInformation DOMAIN_OBJECT = new MailboxesExportTask.AdditionalInformation( + Username.of("bob"), INSTANT); + + @Test + void shouldMatchJsonSerializationContract() throws Exception { + JsonSerializationVerifier.dtoModule(MailboxesExportTaskAdditionalInformationDTO.SERIALIZATION_MODULE) + .bean(DOMAIN_OBJECT) + .json(ClassLoaderUtils.getSystemResourceAsString("json/mailboxesExport.additionalInformation.json")) + .verify(); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskSerializationTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskSerializationTest.java new file mode 100644 index 0000000..0af5143 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/MailboxesExportTaskSerializationTest.java @@ -0,0 +1,45 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you under the Apache License, Version 2.0 (the * + * "License"); you may not use this file except in compliance * + * with the License. You may obtain a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, * + * software distributed under the License is distributed on an * + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * + * KIND, either express or implied. See the License for the * + * specific language governing permissions and limitations * + * under the License. * + ****************************************************************/ + +package org.apache.james.webadmin.service; + +import static org.mockito.Mockito.mock; + +import org.apache.james.JsonSerializationVerifier; +import org.apache.james.core.Username; +import org.apache.james.util.ClassLoaderUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +class MailboxesExportTaskSerializationTest { + ExportService service; + + @BeforeEach + void setUp() { + service = mock(ExportService.class); + } + + @Test + void shouldMatchJsonSerializationContract() throws Exception { + JsonSerializationVerifier.dtoModule(MailboxesExportTask.module(service)) + .bean(new MailboxesExportTask(service, Username.of("bob"))) + .json(ClassLoaderUtils.getSystemResourceAsString("json/mailboxesExport.task.json")) + .verify(); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.additionalInformation.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.additionalInformation.json new file mode 100644 index 0000000..181a96c --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.additionalInformation.json @@ -0,0 +1,5 @@ +{ + "type":"MailboxesExportTask", + "timestamp":"2007-12-03T10:15:30Z", + "username": "bob" +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.task.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.task.json new file mode 100644 index 0000000..419a9d2 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/mailboxesExport.task.json @@ -0,0 +1,4 @@ +{ + "type":"MailboxesExportTask", + "username": "bob" +} \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: server-dev-unsubscr...@james.apache.org For additional commands, e-mail: server-dev-h...@james.apache.org