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 8ea323f41535b864c26dde5177ec1c6331a2b070 Author: Benoit TELLIER <[email protected]> AuthorDate: Sat Sep 13 23:36:53 2025 +0200 JAMES-3758 Expiration: specific user and possibility to use saved date Refactor the class to choose between the different message listing strategies. We did also review the reactive chain to make it more readable. --- .../modules/servers/partials/operate/webadmin.adoc | 4 + .../james/webadmin/routes/MessagesRoutes.java | 17 +- .../webadmin/service/ExpireMailboxService.java | 190 ++++++++++++++---- .../james/webadmin/service/ExpireMailboxTask.java | 3 +- .../webadmin/routes/MessageRoutesExpireTest.java | 215 ++++++++++++++++++++- .../james/webadmin/routes/MessageRoutesTest.java | 3 +- .../webadmin/service/ExpireMailboxServiceTest.java | 49 +++-- ...ireMailboxTaskAdditionalInformationDTOTest.java | 34 +++- .../ExpireMailboxTaskSerializationTest.java | 41 +++- .../expireMailbox.additionalInformation.v2.1.json | 15 ++ .../expireMailbox.additionalInformation.v2.json | 16 ++ .../resources/json/expireMailbox.age.task.v2.json | 10 + .../json/expireMailbox.header.task.v2.json | 10 + 13 files changed, 525 insertions(+), 82 deletions(-) diff --git a/docs/modules/servers/partials/operate/webadmin.adoc b/docs/modules/servers/partials/operate/webadmin.adoc index bea121ca14..c42505965a 100644 --- a/docs/modules/servers/partials/operate/webadmin.adoc +++ b/docs/modules/servers/partials/operate/webadmin.adoc @@ -1521,6 +1521,10 @@ Since this is a somewhat expensive operation, the task is throttled to one user per second. You may speed it up via `usersPerSecond=10` for example. But keep in mind that a high rate might overwhelm your database or blob store. +The following options are also supported: + - `user` query parameter: target a specific user and not all users + - `useSavedDate` query parameter: list all the mails of the mailbox and uses saved date (see RFC-8514) instead of internal date. + *Scanning search only:* (unsupported for Lucene and OpenSearch search implementations) + Some mail clients can add an `Expires` header (RFC 4021) to their messages. Instead of specifying an absolute age, you may choose to delete only such diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MessagesRoutes.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MessagesRoutes.java index a20ecc88be..44db76b497 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MessagesRoutes.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/routes/MessagesRoutes.java @@ -27,10 +27,12 @@ import java.util.Set; import jakarta.inject.Inject; import jakarta.inject.Named; +import org.apache.james.core.Username; import org.apache.james.mailbox.indexer.MessageIdReIndexer; import org.apache.james.mailbox.model.MessageId; import org.apache.james.task.Task; import org.apache.james.task.TaskManager; +import org.apache.james.user.api.UsersRepository; import org.apache.james.webadmin.Routes; import org.apache.james.webadmin.service.ExpireMailboxService; import org.apache.james.webadmin.service.ExpireMailboxTask; @@ -40,6 +42,9 @@ 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.Throwing; +import com.google.common.base.Preconditions; + import spark.Request; import spark.Route; import spark.Service; @@ -55,19 +60,21 @@ public class MessagesRoutes implements Routes { private final ExpireMailboxService expireMailboxService; private final JsonTransformer jsonTransformer; private final Set<TaskFromRequestRegistry.TaskRegistration> allMessagesTaskRegistration; + private final UsersRepository usersRepository; public static final String ALL_MESSAGES_TASKS = "allMessagesTasks"; @Inject MessagesRoutes(TaskManager taskManager, MessageId.Factory messageIdFactory, MessageIdReIndexer reIndexer, ExpireMailboxService expireMailboxService, JsonTransformer jsonTransformer, - @Named(ALL_MESSAGES_TASKS) Set<TaskFromRequestRegistry.TaskRegistration> allMessagesTaskRegistration) { + @Named(ALL_MESSAGES_TASKS) Set<TaskFromRequestRegistry.TaskRegistration> allMessagesTaskRegistration, UsersRepository usersRepository) { this.taskManager = taskManager; this.messageIdFactory = messageIdFactory; this.reIndexer = reIndexer; this.expireMailboxService = expireMailboxService; this.jsonTransformer = jsonTransformer; this.allMessagesTaskRegistration = allMessagesTaskRegistration; + this.usersRepository = usersRepository; } @Override @@ -90,7 +97,13 @@ public class MessagesRoutes implements Routes { Optional.ofNullable(request.queryParams("byExpiresHeader")), Optional.ofNullable(request.queryParams("olderThan")), Optional.ofNullable(request.queryParams("usersPerSecond")), - Optional.ofNullable(request.queryParams("mailbox"))); + Optional.ofNullable(request.queryParams("mailbox")), + request.queryParams().contains("useSavedDate"), + Optional.ofNullable(request.queryParams("user"))); + + runningOptions.getUser() + .ifPresent(Throwing.consumer(user -> Preconditions.checkArgument(usersRepository.contains(Username.of(user)), "user does not exist"))); + return new ExpireMailboxTask(expireMailboxService, runningOptions); } catch (IllegalArgumentException e) { throw ErrorResponder.builder() diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxService.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxService.java index e859ba0d59..5aa5256dd1 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxService.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxService.java @@ -19,6 +19,7 @@ package org.apache.james.webadmin.service; +import java.time.Clock; import java.time.Duration; import java.time.temporal.ChronoUnit; import java.util.Date; @@ -28,6 +29,7 @@ import java.util.concurrent.atomic.AtomicLong; import jakarta.inject.Inject; +import org.apache.commons.lang3.tuple.Pair; import org.apache.james.core.Username; import org.apache.james.mailbox.MailboxManager; import org.apache.james.mailbox.MailboxSession; @@ -35,8 +37,11 @@ import org.apache.james.mailbox.MessageManager; 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.model.FetchGroup; import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.mailbox.model.MailboxPath; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.model.MessageResult; import org.apache.james.mailbox.model.SearchQuery; import org.apache.james.mailbox.model.SearchQuery.DateResolution; import org.apache.james.task.Task; @@ -60,18 +65,21 @@ import reactor.core.publisher.Mono; public class ExpireMailboxService { public static class RunningOptions { - public static final RunningOptions DEFAULT = new RunningOptions(1, MailboxConstants.INBOX, true, Optional.empty()); + public static final RunningOptions DEFAULT = new RunningOptions(1, MailboxConstants.INBOX, + Optional.of(false), Optional.empty(), true, Optional.empty()); public static RunningOptions fromParams( Optional<String> byExpiresHeader, Optional<String> olderThan, - Optional<String> usersPerSecond, Optional<String> mailbox) { + Optional<String> usersPerSecond, Optional<String> mailbox, + boolean useSavedDate, Optional<String> user) { try { if (byExpiresHeader.isPresent() == olderThan.isPresent()) { throw new IllegalArgumentException("Must specify either 'olderThan' or 'byExpiresHeader' parameter"); } return new RunningOptions( usersPerSecond.map(Integer::parseInt).orElse(DEFAULT.getUsersPerSecond()), - mailbox.orElse(DEFAULT.getMailbox()), byExpiresHeader.isPresent(), olderThan); + mailbox.orElse(DEFAULT.getMailbox()), Optional.of(useSavedDate), user, + byExpiresHeader.isPresent(), olderThan); } catch (NumberFormatException ex) { throw new IllegalArgumentException("'usersPerSecond' must be numeric"); } @@ -84,6 +92,8 @@ public class ExpireMailboxService { private final boolean byExpiresHeader; private final Optional<String> olderThan; + private final Optional<Boolean> useSavedDate; + private final Optional<String> user; @JsonIgnore private final Optional<Duration> maxAgeDuration; @@ -91,12 +101,16 @@ public class ExpireMailboxService { @JsonCreator public RunningOptions(@JsonProperty("usersPerSecond") int usersPerSecond, @JsonProperty("mailbox") String mailbox, + @JsonProperty("useSavedDate") Optional<Boolean> useSavedDate, + @JsonProperty("user") Optional<String> user, @JsonProperty("byExpiresHeader") boolean byExpiresHeader, @JsonProperty("olderThan") Optional<String> olderThan) { Preconditions.checkArgument(usersPerSecond > 0, "'usersPerSecond' must be strictly positive"); this.usersPerSecond = usersPerSecond; this.mailbox = mailbox; this.byExpiresHeader = byExpiresHeader; + this.useSavedDate = useSavedDate; + this.user = user; this.olderThan = olderThan; this.maxAgeDuration = olderThan.map(v -> DurationParser.parse(olderThan.get(), ChronoUnit.DAYS)); } @@ -116,6 +130,14 @@ public class ExpireMailboxService { public Optional<String> getOlderThan() { return olderThan; } + + public Optional<Boolean> getUseSavedDate() { + return useSavedDate; + } + + public Optional<String> getUser() { + return user; + } } public static class Context { @@ -164,69 +186,142 @@ public class ExpireMailboxService { } } + private interface MessageListingStrategy { + Mono<List<MessageUid>> listMessages(MessageManager messageManager, RunningOptions runningOptions, MailboxSession session); + + class InternalDateBeforeListingStrategy implements MessageListingStrategy { + private final Clock clock; + + public InternalDateBeforeListingStrategy(Clock clock) { + this.clock = clock; + } + + @Override + public Mono<List<MessageUid>> listMessages(MessageManager messageManager, RunningOptions runningOptions, MailboxSession session) { + Preconditions.checkArgument(runningOptions.maxAgeDuration.isPresent()); + + Date limit = Date.from(clock.instant().minus(runningOptions.maxAgeDuration.get())); + SearchQuery.Criterion internalDateBefore = SearchQuery.internalDateBefore(limit, DateResolution.Second); + try { + return Flux.from(messageManager.search(SearchQuery.of(internalDateBefore), session)) + .collectList(); + } catch (MailboxException e) { + return Mono.error(e); + } + } + } + + class SavedDateDateBeforeListingStrategy implements MessageListingStrategy { + private final Clock clock; + + public SavedDateDateBeforeListingStrategy(Clock clock) { + this.clock = clock; + } + + @Override + public Mono<List<MessageUid>> listMessages(MessageManager messageManager, RunningOptions runningOptions, MailboxSession session) { + Preconditions.checkArgument(runningOptions.maxAgeDuration.isPresent()); + Preconditions.checkArgument(runningOptions.getUseSavedDate().equals(Optional.of(true))); + + Date limit = Date.from(clock.instant().minus(runningOptions.maxAgeDuration.get())); + + return Flux.from(messageManager.getMessagesReactive(MessageRange.all(), FetchGroup.MINIMAL, session)) + .filter(message -> message.getSaveDate().map(savedDate -> savedDate.compareTo(limit) < 0).orElse(true)) + .map(MessageResult::getUid) + .collectList(); + } + } + + class HeaderBasedMessageListingStrategy implements MessageListingStrategy { + private final Clock clock; + + public HeaderBasedMessageListingStrategy(Clock clock) { + this.clock = clock; + } + + @Override + public Mono<List<MessageUid>> listMessages(MessageManager messageManager, RunningOptions runningOptions, MailboxSession session) { + SearchQuery.Criterion criterion = SearchQuery.headerDateBefore("Expires", Date.from(clock.instant()), DateResolution.Second); + try { + return Flux.from(messageManager.search(SearchQuery.of(criterion), session)) + .collectList(); + } catch (MailboxException e) { + return Mono.error(e); + } + } + } + + class Factory { + private final Clock clock; + + public Factory(Clock clock) { + this.clock = clock; + } + + MessageListingStrategy choose(RunningOptions runningOptions) { + if (runningOptions.byExpiresHeader) { + return new HeaderBasedMessageListingStrategy(clock); + } + Preconditions.checkArgument(runningOptions.maxAgeDuration.isPresent()); + if (runningOptions.getUseSavedDate().equals(Optional.of(true))) { + return new SavedDateDateBeforeListingStrategy(clock); + } + return new InternalDateBeforeListingStrategy(clock); + } + } + } + private static final Logger LOGGER = LoggerFactory.getLogger(ExpireMailboxService.class); private final UsersRepository usersRepository; private final MailboxManager mailboxManager; + private final MessageListingStrategy.Factory factory; @Inject - public ExpireMailboxService(UsersRepository usersRepository, MailboxManager mailboxManager) { + public ExpireMailboxService(UsersRepository usersRepository, MailboxManager mailboxManager, Clock clock) { this.usersRepository = usersRepository; this.mailboxManager = mailboxManager; + this.factory = new MessageListingStrategy.Factory(clock); } - public Mono<Result> expireMailboxes(Context context, RunningOptions runningOptions, Date now) { - SearchQuery expiration = SearchQuery.of( - runningOptions.maxAgeDuration.map(maxAge -> { - Date limit = Date.from(now.toInstant().minus(maxAge)); - return SearchQuery.internalDateBefore(limit, DateResolution.Second); - }).orElse(SearchQuery.headerDateBefore("Expires", now, DateResolution.Second))); - - return Flux.from(usersRepository.listReactive()) + public Mono<Result> expireMailboxes(Context context, RunningOptions runningOptions) { + return users(runningOptions) .transform(ReactorUtils.<Username, Task.Result>throttle() .elements(runningOptions.getUsersPerSecond()) .per(Duration.ofSeconds(1)) - .forOperation(username -> - expireUserMailbox(context, username, runningOptions.getMailbox(), expiration))) + .forOperation(username -> loadMailbox(runningOptions, username) + .flatMap(mailboxWithSession -> expireMessages(context, runningOptions, mailboxWithSession)))) .reduce(Task.Result.COMPLETED, Task::combine) - .onErrorResume(UsersRepositoryException.class, e -> { LOGGER.error("Error while accessing users from repository", e); return Mono.just(Task.Result.PARTIAL); }); } - private Mono<Result> expireUserMailbox(Context context, Username username, String mailbox, SearchQuery expiration) { + private Flux<Username> users(RunningOptions runningOptions) { + return runningOptions.user + .map(Username::of) + .map(Flux::just) + .orElseGet(() -> Flux.from(usersRepository.listReactive())); + } + + private Mono<Pair<MessageManager, MailboxSession>> loadMailbox(RunningOptions runningOptions, Username username) { MailboxSession session = mailboxManager.createSystemSession(username); - MailboxPath mailboxPath = MailboxPath.forUser(username, mailbox); + MailboxPath mailboxPath = MailboxPath.forUser(username, runningOptions.getMailbox()); + return Mono.from(mailboxManager.getMailboxReactive(mailboxPath, session)) // newly created users do not have mailboxes yet, just skip them .onErrorResume(MailboxNotFoundException.class, ignore -> Mono.empty()) - .flatMap(mgr -> searchMessagesReactive(mgr, session, expiration) - .flatMap(list -> deleteMessagesReactive(mgr, session, list))) - .doOnNext(expired -> { - if (expired > 0) { - context.incrementExpiredCount(); - context.incrementMessagesDeleted(expired); - } - context.incrementProcessedCount(); - }) - .then(Mono.just(Task.Result.COMPLETED)) - .onErrorResume(e -> { - LOGGER.warn("Failed to expire user mailbox {}", username, e); - context.incrementFailedCount(); - context.incrementProcessedCount(); - return Mono.just(Task.Result.PARTIAL); - }) - .doFinally(any -> mailboxManager.endProcessingRequest(session)); + .map(messageManager -> Pair.of(messageManager, session)); } - private Mono<List<MessageUid>> searchMessagesReactive(MessageManager mgr, MailboxSession session, SearchQuery expiration) { - try { - return Flux.from(mgr.search(expiration, session)).collectList(); - } catch (MailboxException e) { - return Mono.error(e); - } + private Mono<Result> expireMessages(Context context, RunningOptions runningOptions, Pair<MessageManager, MailboxSession> mailboxWithSession) { + return factory.choose(runningOptions) + .listMessages(mailboxWithSession.getKey(), runningOptions, mailboxWithSession.getValue()) + .flatMap(uids -> deleteMessagesReactive(mailboxWithSession.getKey(), mailboxWithSession.getValue(), uids)) + .doOnNext(expired -> recordSuccess(context, expired)) + .then(Mono.just(Result.COMPLETED)) + .onErrorResume(e -> manageFailure(context, mailboxWithSession, e)); } private Mono<Integer> deleteMessagesReactive(MessageManager mgr, MailboxSession session, List<MessageUid> uids) { @@ -237,4 +332,19 @@ public class ExpireMailboxService { .thenReturn(uids.size()); } } + + private Mono<Result> manageFailure(Context context, Pair<MessageManager, MailboxSession> mailboxWithSession, Throwable e) { + LOGGER.warn("Failed to expire user mailbox {}", mailboxWithSession.getValue().getUser().asString(), e); + context.incrementFailedCount(); + context.incrementProcessedCount(); + return Mono.just(Result.PARTIAL); + } + + private void recordSuccess(Context context, Integer expired) { + if (expired > 0) { + context.incrementExpiredCount(); + context.incrementMessagesDeleted(expired); + } + context.incrementProcessedCount(); + } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxTask.java b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxTask.java index cd572b97c2..86a5b411bb 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxTask.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/main/java/org/apache/james/webadmin/service/ExpireMailboxTask.java @@ -21,7 +21,6 @@ package org.apache.james.webadmin.service; import java.time.Clock; import java.time.Instant; -import java.util.Date; import java.util.Optional; import jakarta.inject.Inject; @@ -110,7 +109,7 @@ public class ExpireMailboxTask implements AsyncSafeTask { @Override public Publisher<Result> runAsync() { - return expireMailboxService.expireMailboxes(context, runningOptions, new Date()); + return expireMailboxService.expireMailboxes(context, runningOptions); } @Override diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesExpireTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesExpireTest.java index 026e6ad1c6..2926f3a272 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesExpireTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesExpireTest.java @@ -26,6 +26,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; +import java.time.Clock; import java.util.Date; import org.apache.james.core.Username; @@ -61,7 +62,9 @@ import io.restassured.RestAssured; class MessageRoutesExpireTest { private static final DomainList NO_DOMAIN_LIST = null; private static final Username USERNAME = Username.of("benwa"); + private static final Username USERNAME_2 = Username.of("benwa2"); private static final MailboxPath INBOX = MailboxPath.inbox(USERNAME); + private static final MailboxPath INBOX_2 = MailboxPath.inbox(USERNAME_2); private WebAdminServer webAdminServer; private InMemoryMailboxManager mailboxManager; @@ -82,9 +85,10 @@ class MessageRoutesExpireTest { new MessagesRoutes(taskManager, new InMemoryMessageId.Factory(), null, - new ExpireMailboxService(usersRepository, mailboxManager), + new ExpireMailboxService(usersRepository, mailboxManager, Clock.systemUTC()), jsonTransformer, - ImmutableSet.of())) + ImmutableSet.of(), + usersRepository)) .start(); RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer).build(); @@ -173,6 +177,18 @@ class MessageRoutesExpireTest { .body("details", is("'usersPerSecond' must be strictly positive")); } + @Test + void expireMailboxShouldFailWithNonExistingUser() { + when() + .delete("/messages?byExpiresHeader&user=notfound") + .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("user does not exist")); + } + } @Nested @@ -235,6 +251,201 @@ class MessageRoutesExpireTest { .body("additionalInformation.mailboxesProcessed", is(1)) .body("additionalInformation.messagesDeleted", is(1)); } + + @Test + void expireMailboxShouldNotRemoveMailsWhenNotExpired() throws Exception { + usersRepository.addUser(USERNAME, "secret"); + 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).getId(); + + String taskId = when() + .delete("/messages?olderThan=1s") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("type", Matchers.is("ExpireMailboxTask")) + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("additionalInformation.type", is("ExpireMailboxTask")) + .body("additionalInformation.runningOptions.usersPerSecond", is(RunningOptions.DEFAULT.getUsersPerSecond())) + .body("additionalInformation.runningOptions.byExpiresHeader", is(false)) + .body("additionalInformation.runningOptions.olderThan", is("1s")) + .body("additionalInformation.mailboxesExpired", is(0)) + .body("additionalInformation.mailboxesFailed", is(0)) + .body("additionalInformation.mailboxesProcessed", is(1)) + .body("additionalInformation.messagesDeleted", is(0)); + } + + @Test + void expireMailboxShouldIgnoreOldInternalDateWhenUseSavedDate() throws Exception { + usersRepository.addUser(USERNAME, "secret"); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + mailboxManager.createMailbox(INBOX, systemSession).get(); + mailboxManager.getMailbox(INBOX, systemSession).appendMessage( + MessageManager.AppendCommand.builder() + .withInternalDate(new Date(System.currentTimeMillis() - 60000)) + .build("header: value\r\n\r\nbody"), + systemSession).getId(); + + String taskId = given() + .queryParam("olderThan", "5s") + .queryParam("useSavedDate") + .delete("/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("type", Matchers.is("ExpireMailboxTask")) + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("additionalInformation.type", is("ExpireMailboxTask")) + .body("additionalInformation.runningOptions.usersPerSecond", is(RunningOptions.DEFAULT.getUsersPerSecond())) + .body("additionalInformation.runningOptions.byExpiresHeader", is(false)) + .body("additionalInformation.runningOptions.olderThan", is("5s")) + .body("additionalInformation.mailboxesExpired", is(0)) + .body("additionalInformation.mailboxesFailed", is(0)) + .body("additionalInformation.mailboxesProcessed", is(1)) + .body("additionalInformation.messagesDeleted", is(0)); + } + + @Test + void expireMailboxShouldCleanOldEnoughSavedDate() throws Exception { + usersRepository.addUser(USERNAME, "secret"); + 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).getId(); + + Thread.sleep(2000); + + String taskId = given() + .queryParam("olderThan", "1s") + .queryParam("useSavedDate") + .delete("/messages") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("type", Matchers.is("ExpireMailboxTask")) + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("additionalInformation.type", is("ExpireMailboxTask")) + .body("additionalInformation.runningOptions.usersPerSecond", is(RunningOptions.DEFAULT.getUsersPerSecond())) + .body("additionalInformation.runningOptions.byExpiresHeader", is(false)) + .body("additionalInformation.runningOptions.olderThan", is("1s")) + .body("additionalInformation.mailboxesExpired", is(1)) + .body("additionalInformation.mailboxesFailed", is(0)) + .body("additionalInformation.mailboxesProcessed", is(1)) + .body("additionalInformation.messagesDeleted", is(1)); + } + + @Test + void expireMailboxShouldProcessAllUsers() throws Exception { + usersRepository.addUser(USERNAME, "secret"); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + mailboxManager.createMailbox(INBOX, systemSession).get(); + mailboxManager.getMailbox(INBOX, systemSession).appendMessage( + MessageManager.AppendCommand.builder() + .withInternalDate(new Date(System.currentTimeMillis() - 5000)) + .build("header: value\r\n\r\nbody"), + systemSession).getId(); + + usersRepository.addUser(USERNAME_2, "secret"); + MailboxSession systemSession2 = mailboxManager.createSystemSession(USERNAME_2); + mailboxManager.createMailbox(INBOX_2, systemSession2).get(); + mailboxManager.getMailbox(INBOX_2, systemSession2).appendMessage( + MessageManager.AppendCommand.builder() + .withInternalDate(new Date(System.currentTimeMillis() - 5000)) + .build("header: value\r\n\r\nbody"), + systemSession2).getId(); + + String taskId = when() + .delete("/messages?olderThan=1s") + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("type", Matchers.is("ExpireMailboxTask")) + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("additionalInformation.type", is("ExpireMailboxTask")) + .body("additionalInformation.runningOptions.usersPerSecond", is(RunningOptions.DEFAULT.getUsersPerSecond())) + .body("additionalInformation.runningOptions.byExpiresHeader", is(false)) + .body("additionalInformation.runningOptions.olderThan", is("1s")) + .body("additionalInformation.mailboxesExpired", is(2)) + .body("additionalInformation.mailboxesFailed", is(0)) + .body("additionalInformation.mailboxesProcessed", is(2)) + .body("additionalInformation.messagesDeleted", is(2)); + } + + @Test + void expireMailboxShouldBeLimitedToUserParameterWhenSupplied() throws Exception { + usersRepository.addUser(USERNAME, "secret"); + MailboxSession systemSession = mailboxManager.createSystemSession(USERNAME); + mailboxManager.createMailbox(INBOX, systemSession).get(); + mailboxManager.getMailbox(INBOX, systemSession).appendMessage( + MessageManager.AppendCommand.builder() + .withInternalDate(new Date(System.currentTimeMillis() - 5000)) + .build("header: value\r\n\r\nbody"), + systemSession).getId(); + + usersRepository.addUser(USERNAME_2, "secret"); + MailboxSession systemSession2 = mailboxManager.createSystemSession(USERNAME_2); + mailboxManager.createMailbox(INBOX_2, systemSession2).get(); + mailboxManager.getMailbox(INBOX_2, systemSession2).appendMessage( + MessageManager.AppendCommand.builder() + .withInternalDate(new Date(System.currentTimeMillis() - 5000)) + .build("header: value\r\n\r\nbody"), + systemSession2).getId(); + + String taskId = given() + .queryParam("olderThan", "1s") + .queryParam("user", USERNAME.asString()) + .delete("/messages") + + .jsonPath() + .get("taskId"); + + given() + .basePath(TasksRoutes.BASE) + .when() + .get(taskId + "/await") + .then() + .body("type", Matchers.is("ExpireMailboxTask")) + .body("status", is("completed")) + .body("taskId", is(notNullValue())) + .body("additionalInformation.type", is("ExpireMailboxTask")) + .body("additionalInformation.runningOptions.usersPerSecond", is(RunningOptions.DEFAULT.getUsersPerSecond())) + .body("additionalInformation.runningOptions.byExpiresHeader", is(false)) + .body("additionalInformation.runningOptions.olderThan", is("1s")) + .body("additionalInformation.mailboxesExpired", is(1)) + .body("additionalInformation.mailboxesFailed", is(0)) + .body("additionalInformation.mailboxesProcessed", is(1)) + .body("additionalInformation.messagesDeleted", is(1)); + } } @Nested diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesTest.java index 1dd356c446..5171283246 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/routes/MessageRoutesTest.java @@ -95,7 +95,8 @@ class MessageRoutesTest { new MessageIdReIndexerImpl(reIndexerPerformer), null, jsonTransformer, - ImmutableSet.of())) + ImmutableSet.of(), + null)) .start(); RestAssured.requestSpecification = WebAdminUtils.buildRequestSpecification(webAdminServer).build(); diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxServiceTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxServiceTest.java index 360ebeb502..c65ae91667 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxServiceTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxServiceTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.nio.charset.StandardCharsets; +import java.time.Clock; import java.time.ZonedDateTime; import java.util.Collection; import java.util.Date; @@ -58,7 +59,7 @@ import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; -public class ExpireMailboxServiceTest { +class ExpireMailboxServiceTest { private static class FailingSearchIndex implements MessageSearchIndex { @@ -100,7 +101,8 @@ public class ExpireMailboxServiceTest { } } - private static final ExpireMailboxService.RunningOptions OLDER_THAN_1S = new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, false, Optional.of("1s")); + private static final ExpireMailboxService.RunningOptions OLDER_THAN_1S = new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.of(false), Optional.empty(),false, Optional.of("1s")); private final Username alice = Username.of("[email protected]"); private final MailboxPath aliceInbox = MailboxPath.inbox(alice); @@ -133,7 +135,7 @@ public class ExpireMailboxServiceTest { mailboxManager = resources.getMailboxManager(); aliceSession = mailboxManager.createSystemSession(alice); - testee = new ExpireMailboxService(usersRepository, mailboxManager); + testee = new ExpireMailboxService(usersRepository, mailboxManager, Clock.systemUTC()); } private static Date asDate(ZonedDateTime dateTime) { @@ -161,8 +163,7 @@ public class ExpireMailboxServiceTest { when(usersRepository.listReactive()).thenReturn(Flux.error(new UsersRepositoryException("it is broken"))); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.PARTIAL); assertThat(context.getInboxesExpired()).isEqualTo(0); @@ -178,8 +179,7 @@ public class ExpireMailboxServiceTest { // intentionally no mailbox creation ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(0); @@ -195,8 +195,7 @@ public class ExpireMailboxServiceTest { mailboxManager.createMailbox(aliceInbox, aliceSession); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(0); @@ -217,8 +216,7 @@ public class ExpireMailboxServiceTest { searchIndex.generateFailures(1); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.PARTIAL); assertThat(context.getInboxesExpired()).isEqualTo(0); @@ -236,8 +234,7 @@ public class ExpireMailboxServiceTest { appendMessage(aliceManager, aliceSession, ZonedDateTime.now().minusSeconds(5)); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(1); @@ -256,20 +253,19 @@ public class ExpireMailboxServiceTest { MessageManager aliceManager = mailboxManager.getMailbox(aliceInbox, aliceSession); ZonedDateTime created = ZonedDateTime.now(); - ZonedDateTime expires = created.plusSeconds(5); - ZonedDateTime now = expires.plusSeconds(10); + ZonedDateTime expires = created.minusSeconds(5); appendMessage(aliceManager, aliceSession, Message.Builder.of() .setSubject("test") .setBody("whatever", StandardCharsets.UTF_8) .setDate(asDate(created)) .setField(Fields.date("Expires", asDate(expires), TimeZone.getTimeZone(expires.getZone()))) - .build() - ); + .build()); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, true, Optional.empty()); - Task.Result result = testee.expireMailboxes(context, options, asDate(now)).block(); + ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.of(false), Optional.empty(), true, Optional.empty()); + Task.Result result = testee.expireMailboxes(context, options).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(1); @@ -291,9 +287,9 @@ public class ExpireMailboxServiceTest { appendMessage(aliceManager, aliceSession, ZonedDateTime.now().minusSeconds(5)); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, mailboxName, false, Optional.of("1s")); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, options, now).block(); + ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, mailboxName, + Optional.of(false), Optional.empty(), false, Optional.of("1s")); + Task.Result result = testee.expireMailboxes(context, options).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(1); @@ -309,9 +305,9 @@ public class ExpireMailboxServiceTest { when(usersRepository.listReactive()).thenReturn(Flux.just(alice)); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, "NoSuchMailbox", false, Optional.of("1s")); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, options, now).block(); + ExpireMailboxService.RunningOptions options = new ExpireMailboxService.RunningOptions(1, "NoSuchMailbox", + Optional.of(false), Optional.empty(), false, Optional.of("1s")); + Task.Result result = testee.expireMailboxes(context, options).block(); assertThat(result).isEqualTo(Task.Result.COMPLETED); assertThat(context.getInboxesExpired()).isEqualTo(0); @@ -339,8 +335,7 @@ public class ExpireMailboxServiceTest { searchIndex.generateFailures(1); ExpireMailboxService.Context context = new ExpireMailboxService.Context(); - Date now = new Date(); - Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S, now).block(); + Task.Result result = testee.expireMailboxes(context, OLDER_THAN_1S).block(); assertThat(result).isEqualTo(Task.Result.PARTIAL); assertThat(context.getInboxesExpired()).isEqualTo(1); diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskAdditionalInformationDTOTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskAdditionalInformationDTOTest.java index 606c0cd95f..bfd039e400 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskAdditionalInformationDTOTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskAdditionalInformationDTOTest.java @@ -19,25 +19,53 @@ package org.apache.james.webadmin.service; +import static org.apache.james.JsonSerializationVerifier.recursiveComparisonConfiguration; +import static org.assertj.core.api.Assertions.assertThat; + import java.time.Instant; import java.util.Optional; import org.apache.james.JsonSerializationVerifier; +import org.apache.james.json.JsonGenericSerializer; import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.util.ClassLoaderUtils; import org.junit.jupiter.api.Test; -public class ExpireMailboxTaskAdditionalInformationDTOTest { +class ExpireMailboxTaskAdditionalInformationDTOTest { private static final Instant INSTANT = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final ExpireMailboxTask.AdditionalInformation LEGACY_DOMAIN_OBJECT = new ExpireMailboxTask.AdditionalInformation( + INSTANT, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, Optional.empty(), Optional.empty(), false, Optional.of("90d")), 5, 2, 10, 234); private static final ExpireMailboxTask.AdditionalInformation DOMAIN_OBJECT = new ExpireMailboxTask.AdditionalInformation( - INSTANT, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, false, Optional.of("90d")), 5, 2, 10, 234); + INSTANT, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, Optional.of(true), Optional.of("user"), false, Optional.of("90d")), 5, 2, 10, 234); + private static final ExpireMailboxTask.AdditionalInformation DOMAIN_OBJECT_2 = new ExpireMailboxTask.AdditionalInformation( + INSTANT, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, Optional.of(false), Optional.empty(), true, Optional.of("90d")), 5, 2, 10, 234); @Test void shouldMatchJsonSerializationContract() throws Exception { JsonSerializationVerifier.dtoModule(ExpireMailboxAdditionalInformationDTO.module()) .bean(DOMAIN_OBJECT) - .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.additionalInformation.json")) + .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.additionalInformation.v2.json")) + .verify(); + } + + @Test + void shouldMatchJsonSerializationContract2() throws Exception { + JsonSerializationVerifier.dtoModule(ExpireMailboxAdditionalInformationDTO.module()) + .bean(DOMAIN_OBJECT_2) + .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.additionalInformation.v2.1.json")) .verify(); } + + @Test + void shouldDeserializeLegacy() throws Exception { + ExpireMailboxTask.AdditionalInformation actual = JsonGenericSerializer + .forModules(ExpireMailboxAdditionalInformationDTO.module()) + .withoutNestedType() + .deserialize(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.additionalInformation.json")); + + assertThat(actual) + .usingRecursiveComparison(recursiveComparisonConfiguration) + .isEqualTo(LEGACY_DOMAIN_OBJECT); + } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskSerializationTest.java b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskSerializationTest.java index 0f734e35d1..b4445d4f58 100644 --- a/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskSerializationTest.java +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/java/org/apache/james/webadmin/service/ExpireMailboxTaskSerializationTest.java @@ -19,17 +19,20 @@ package org.apache.james.webadmin.service; +import static org.apache.james.JsonSerializationVerifier.recursiveComparisonConfiguration; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; import java.util.Optional; import org.apache.james.JsonSerializationVerifier; +import org.apache.james.json.JsonGenericSerializer; import org.apache.james.mailbox.model.MailboxConstants; import org.apache.james.util.ClassLoaderUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -public class ExpireMailboxTaskSerializationTest { +class ExpireMailboxTaskSerializationTest { private ExpireMailboxService expireMailboxService; @BeforeEach @@ -40,16 +43,44 @@ public class ExpireMailboxTaskSerializationTest { @Test void shouldMatchJsonSerializationContractWithOlderThan() throws Exception { JsonSerializationVerifier.dtoModule(ExpireMailboxDTO.module(expireMailboxService)) - .bean(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, false, Optional.of("90d")))) - .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.age.task.json")) + .bean(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.of(false), Optional.empty(), false, Optional.of("90d")))) + .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.age.task.v2.json")) .verify(); } @Test void shouldMatchJsonSerializationContractWithExpiresHeader() throws Exception { JsonSerializationVerifier.dtoModule(ExpireMailboxDTO.module(expireMailboxService)) - .bean(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, true, Optional.empty()))) - .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.header.task.json")) + .bean(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.of(true), Optional.of("bob"), true, Optional.empty()))) + .json(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.header.task.v2.json")) .verify(); } + + @Test + void shouldDeserializeLegacyWhenHeader() throws Exception { + ExpireMailboxTask actual = JsonGenericSerializer + .forModules(ExpireMailboxDTO.module(expireMailboxService)) + .withoutNestedType() + .deserialize(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.age.task.json")); + + assertThat(actual) + .usingRecursiveComparison(recursiveComparisonConfiguration) + .isEqualTo(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.empty(), Optional.empty(), false, Optional.of("90d")))); + } + + @Test + void shouldDeserializeLegacy() throws Exception { + ExpireMailboxTask actual = JsonGenericSerializer + .forModules(ExpireMailboxDTO.module(expireMailboxService)) + .withoutNestedType() + .deserialize(ClassLoaderUtils.getSystemResourceAsString("json/expireMailbox.header.task.json")); + + assertThat(actual) + .usingRecursiveComparison(recursiveComparisonConfiguration) + .isEqualTo(new ExpireMailboxTask(expireMailboxService, new ExpireMailboxService.RunningOptions(1, MailboxConstants.INBOX, + Optional.empty(), Optional.empty(), true, Optional.empty()))); + } } diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.1.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.1.json new file mode 100644 index 0000000000..3985bc41ca --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.1.json @@ -0,0 +1,15 @@ +{ + "mailboxesExpired": 5, + "mailboxesFailed": 2, + "mailboxesProcessed": 10, + "messagesDeleted": 234, + "runningOptions": { + "usersPerSecond": 1, + "mailbox": "INBOX", + "byExpiresHeader": true, + "useSavedDate": false, + "olderThan": "90d" + }, + "timestamp": "2007-12-03T10:15:30Z", + "type": "ExpireMailboxTask" +} diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.json new file mode 100644 index 0000000000..64e5c76532 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.additionalInformation.v2.json @@ -0,0 +1,16 @@ +{ + "mailboxesExpired": 5, + "mailboxesFailed": 2, + "mailboxesProcessed": 10, + "messagesDeleted": 234, + "runningOptions": { + "usersPerSecond": 1, + "mailbox": "INBOX", + "byExpiresHeader": false, + "user": "user", + "useSavedDate": true, + "olderThan": "90d" + }, + "timestamp": "2007-12-03T10:15:30Z", + "type": "ExpireMailboxTask" +} diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.age.task.v2.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.age.task.v2.json new file mode 100644 index 0000000000..e5d463dc4d --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.age.task.v2.json @@ -0,0 +1,10 @@ +{ + "runningOptions": { + "usersPerSecond": 1, + "mailbox": "INBOX", + "byExpiresHeader": false, + "olderThan": "90d", + "useSavedDate":false + }, + "type": "ExpireMailboxTask" +} diff --git a/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.header.task.v2.json b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.header.task.v2.json new file mode 100644 index 0000000000..4baa247670 --- /dev/null +++ b/server/protocols/webadmin/webadmin-mailbox/src/test/resources/json/expireMailbox.header.task.v2.json @@ -0,0 +1,10 @@ +{ + "runningOptions": { + "usersPerSecond": 1, + "mailbox": "INBOX", + "byExpiresHeader": true, + "useSavedDate":true, + "user": "bob" + }, + "type": "ExpireMailboxTask" +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
