You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by bt...@apache.org on 2020/05/04 03:21:28 UTC
[james-project] 09/12: JAMES-3105 Add an option to trust message
denormalization when recomputing counters
This is an automated email from the ASF dual-hosted git repository.
btellier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 4501b921168c7f9b1048f8b1e33a2d64d059aa2e
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Thu Apr 23 17:16:28 2020 +0700
JAMES-3105 Add an option to trust message denormalization when recomputing counters
---
.../mail/task/RecomputeMailboxCountersService.java | 39 +-
.../mail/task/RecomputeMailboxCountersTask.java | 10 +-
.../mail/task/RecomputeMailboxCountersTaskDTO.java | 19 +-
.../task/RecomputeMailboxCountersServiceTest.java | 438 +++++++++++++--------
...omputeMailboxCountersTaskSerializationTest.java | 46 ++-
.../RecomputeMailboxCountersRequestToTask.java | 3 +-
6 files changed, 365 insertions(+), 190 deletions(-)
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
index e14d16e..b39db27 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersService.java
@@ -55,6 +55,30 @@ public class RecomputeMailboxCountersService {
private static final int MAILBOX_CONCURRENCY = 2;
private static final int MESSAGE_CONCURRENCY = 8;
+ public static class Options {
+ public static Options trustMessageDenormalization() {
+ return of(true);
+ }
+
+ public static Options recheckMessageDenormalization() {
+ return of(false);
+ }
+
+ public static Options of(boolean value) {
+ return new Options(value);
+ }
+
+ private final boolean trustMessageDenormalization;
+
+ private Options(boolean trustMessageDenormalization) {
+ this.trustMessageDenormalization = trustMessageDenormalization;
+ }
+
+ public boolean isMessageDenormalizationTrusted() {
+ return trustMessageDenormalization;
+ }
+ }
+
private static class Counter {
private final CassandraId mailboxId;
private final AtomicLong total;
@@ -163,9 +187,9 @@ public class RecomputeMailboxCountersService {
this.counterDAO = counterDAO;
}
- Mono<Result> recomputeMailboxCounters(Context context) {
+ Mono<Result> recomputeMailboxCounters(Context context, Options options) {
return mailboxDAO.retrieveAllMailboxes()
- .flatMap(mailbox -> recomputeMailboxCounter(context, mailbox), MAILBOX_CONCURRENCY)
+ .flatMap(mailbox -> recomputeMailboxCounter(context, mailbox, options), MAILBOX_CONCURRENCY)
.reduce(Result.COMPLETED, Task::combine)
.onErrorResume(e -> {
LOGGER.error("Error listing mailboxes", e);
@@ -173,12 +197,12 @@ public class RecomputeMailboxCountersService {
});
}
- private Mono<Result> recomputeMailboxCounter(Context context, Mailbox mailbox) {
+ private Mono<Result> recomputeMailboxCounter(Context context, Mailbox mailbox, Options options) {
CassandraId mailboxId = (CassandraId) mailbox.getMailboxId();
Counter counter = new Counter(mailboxId);
return imapUidToMessageIdDAO.retrieveMessages(mailboxId, MessageRange.all())
- .flatMap(message -> latestMetadata(mailboxId, message), MESSAGE_CONCURRENCY)
+ .flatMap(message -> latestMetadata(mailboxId, message, options), MESSAGE_CONCURRENCY)
.doOnNext(counter::process)
.then(Mono.defer(() -> counterDAO.resetCounters(counter.snapshot())))
.then(Mono.just(Result.COMPLETED))
@@ -193,7 +217,12 @@ public class RecomputeMailboxCountersService {
});
}
- private Flux<ComposedMessageIdWithMetaData> latestMetadata(CassandraId mailboxId, ComposedMessageIdWithMetaData message) {
+ private Flux<ComposedMessageIdWithMetaData> latestMetadata(CassandraId mailboxId,
+ ComposedMessageIdWithMetaData message,
+ Options options) {
+ if (options.isMessageDenormalizationTrusted()) {
+ return Flux.just(message);
+ }
CassandraMessageId messageId = (CassandraMessageId) message.getComposedMessageId().getMessageId();
return messageIdToImapUidDAO.retrieve(messageId, Optional.of(mailboxId))
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTask.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTask.java
index 74082f3..c93e1ea 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTask.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTask.java
@@ -70,16 +70,18 @@ public class RecomputeMailboxCountersTask implements Task {
}
private final RecomputeMailboxCountersService service;
+ private final RecomputeMailboxCountersService.Options options;
private RecomputeMailboxCountersService.Context context;
- public RecomputeMailboxCountersTask(RecomputeMailboxCountersService service) {
+ public RecomputeMailboxCountersTask(RecomputeMailboxCountersService service, RecomputeMailboxCountersService.Options options) {
this.service = service;
+ this.options = options;
this.context = new RecomputeMailboxCountersService.Context();
}
@Override
public Result run() {
- return service.recomputeMailboxCounters(context)
+ return service.recomputeMailboxCounters(context, options)
.subscribeOn(Schedulers.elastic())
.block();
}
@@ -89,6 +91,10 @@ public class RecomputeMailboxCountersTask implements Task {
return RECOMPUTE_MAILBOX_COUNTERS;
}
+ public RecomputeMailboxCountersService.Options getOptions() {
+ return options;
+ }
+
@Override
public Optional<TaskExecutionDetails.AdditionalInformation> details() {
Snapshot snapshot = context.snapshot();
diff --git a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskDTO.java b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskDTO.java
index b8fa112..d855aa1 100644
--- a/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskDTO.java
+++ b/mailbox/cassandra/src/main/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskDTO.java
@@ -18,7 +18,10 @@
****************************************************************/
package org.apache.james.mailbox.cassandra.mail.task;
+import java.util.Optional;
+
import org.apache.james.json.DTOModule;
+import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService.Options;
import org.apache.james.server.task.json.dto.TaskDTO;
import org.apache.james.server.task.json.dto.TaskDTOModule;
@@ -26,7 +29,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
public class RecomputeMailboxCountersTaskDTO implements TaskDTO {
private static RecomputeMailboxCountersTaskDTO toDTO(RecomputeMailboxCountersTask domainObject, String typeName) {
- return new RecomputeMailboxCountersTaskDTO(typeName);
+ return new RecomputeMailboxCountersTaskDTO(typeName, Optional.of(domainObject.getOptions().isMessageDenormalizationTrusted()));
}
public static TaskDTOModule<RecomputeMailboxCountersTask, RecomputeMailboxCountersTaskDTO> module(RecomputeMailboxCountersService service) {
@@ -40,17 +43,27 @@ public class RecomputeMailboxCountersTaskDTO implements TaskDTO {
}
private final String type;
+ private final Optional<Boolean> trustMessageDenormalization;
- public RecomputeMailboxCountersTaskDTO(@JsonProperty("type") String type) {
+ public RecomputeMailboxCountersTaskDTO(@JsonProperty("type") String type,
+ @JsonProperty("trustMessageDenormalization") Optional<Boolean> trustMessageDenormalization) {
this.type = type;
+ this.trustMessageDenormalization = trustMessageDenormalization;
}
private RecomputeMailboxCountersTask toDomainObject(RecomputeMailboxCountersService service) {
- return new RecomputeMailboxCountersTask(service);
+ Options options = trustMessageDenormalization.map(Options::of).orElse(Options.recheckMessageDenormalization());
+ return new RecomputeMailboxCountersTask(service, options);
}
@Override
+ @JsonProperty("type")
public String getType() {
return type;
}
+
+ @JsonProperty("trustMessageDenormalization")
+ public Optional<Boolean> trustMessageDenormalization() {
+ return trustMessageDenormalization;
+ }
}
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
index 683e1f7..10382a8 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersServiceTest.java
@@ -51,6 +51,8 @@ import org.apache.james.mailbox.model.MailboxPath;
import org.apache.james.mailbox.model.UidValidity;
import org.apache.james.task.Task.Result;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -89,199 +91,297 @@ class RecomputeMailboxCountersServiceTest {
testee = new RecomputeMailboxCountersService(mailboxDAO, imapUidToMessageIdDAO, messageIdToImapUidDAO, counterDAO);
}
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenNoMailboxes() {
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
-
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenMailboxWithNoMessages() {
- mailboxDAO.save(MAILBOX).block();
-
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
-
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenMailboxWithMessages() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
- counterDAO.incrementUnseenAndCount(CASSANDRA_ID_1).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
-
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenMessageDenormalizationIssue() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_SEEN).block();
- counterDAO.incrementUnseenAndCount(CASSANDRA_ID_1).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
+ @Nested
+ class TrustMessageDenormalizationTest implements Contract {
+ @Override
+ public RecomputeMailboxCountersService testee() {
+ return testee;
+ }
- @Test
- void recomputeMailboxCountersShouldReturnCountersAreIncorrect() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
+ @Override
+ public CassandraMailboxDAO mailboxDAO() {
+ return mailboxDAO;
+ }
- testee.recomputeMailboxCounters(new Context()).block();
+ @Override
+ public RecomputeMailboxCountersService.Options options() {
+ return RecomputeMailboxCountersService.Options.trustMessageDenormalization();
+ }
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
-
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenOrphanMailboxRegistration() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- counterDAO.incrementUnseenAndCount(CASSANDRA_ID_1).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
+ @Override
+ public CassandraMessageIdDAO imapUidToMessageIdDAO() {
+ return imapUidToMessageIdDAO;
+ }
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
+ @Override
+ public CassandraMessageIdToImapUidDAO messageIdToImapUidDAO() {
+ return messageIdToImapUidDAO;
+ }
- @Test
- void recomputeMailboxCountersShouldReturnCompletedWhenMailboxListReferenceIsMissing() {
- mailboxDAO.save(MAILBOX).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
- counterDAO.incrementUnseenAndCount(CASSANDRA_ID_1).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
+ @Override
+ public CassandraMailboxCounterDAO counterDAO() {
+ return counterDAO;
+ }
- testee.recomputeMailboxCounters(new Context()).block();
+ @Disabled("Inconsitencies can not be corrected on the fly as trust avoid their detection")
+ @Override
+ public void recomputeMailboxCountersShouldIgnoreMissingMailboxListReferences() {
- assertThat(testee.recomputeMailboxCounters(new Context()).block())
- .isEqualTo(Result.COMPLETED);
- }
+ }
- @Test
- void recomputeMailboxCountersShouldNoopWhenMailboxWithoutMessage() {
- mailboxDAO.save(MAILBOX).block();
+ @Disabled("Inconsitencies can not be corrected on the fly as trust avoid their detection")
+ @Override
+ public void recomputeMailboxCountersShouldUseSourceOfTruthForComputation() {
- testee.recomputeMailboxCounters(new Context()).block();
+ }
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .isEmpty();
- }
+ @Disabled("Inconsitencies can not be corrected on the fly as trust avoid their detection")
+ @Override
+ public void recomputeMailboxCountersShouldIgnoreOrphanMailboxListReference() {
- @Test
- void recomputeMailboxCountersShouldNoopWhenValidCounters() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
- counterDAO.incrementUnseenAndCount(CASSANDRA_ID_1).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .contains(MailboxCounters.builder()
- .mailboxId(CASSANDRA_ID_1)
- .count(1)
- .unseen(1)
- .build());
+ }
}
- @Test
- void recomputeMailboxCountersShouldRecreateMissingCounters() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .contains(MailboxCounters.builder()
- .mailboxId(CASSANDRA_ID_1)
- .count(1)
- .unseen(1)
- .build());
+ @Nested
+ class RecheckMessageDenormalizationTest implements Contract {
+ @Override
+ public RecomputeMailboxCountersService testee() {
+ return testee;
+ }
+
+ @Override
+ public CassandraMailboxDAO mailboxDAO() {
+ return mailboxDAO;
+ }
+
+ @Override
+ public RecomputeMailboxCountersService.Options options() {
+ return RecomputeMailboxCountersService.Options.recheckMessageDenormalization();
+ }
+
+ @Override
+ public CassandraMessageIdDAO imapUidToMessageIdDAO() {
+ return imapUidToMessageIdDAO;
+ }
+
+ @Override
+ public CassandraMessageIdToImapUidDAO messageIdToImapUidDAO() {
+ return messageIdToImapUidDAO;
+ }
+
+ @Override
+ public CassandraMailboxCounterDAO counterDAO() {
+ return counterDAO;
+ }
}
- @Test
- void recomputeMailboxCountersShouldResetIncorrectCounters() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .contains(MailboxCounters.builder()
- .mailboxId(CASSANDRA_ID_1)
- .count(1)
- .unseen(1)
- .build());
- }
+ interface Contract {
+ RecomputeMailboxCountersService testee();
- @Test
- void recomputeMailboxCountersShouldTakeSeenIntoAccount() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_SEEN).block();
- messageIdToImapUidDAO.insert(METADATA_SEEN).block();
- counterDAO.incrementCount(CASSANDRA_ID_1).block();
-
- testee.recomputeMailboxCounters(new Context()).block();
-
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .contains(MailboxCounters.builder()
- .mailboxId(CASSANDRA_ID_1)
- .count(1)
- .unseen(0)
- .build());
- }
+ CassandraMailboxDAO mailboxDAO();
- @Test
- void recomputeMailboxCountersShouldUseSourceOfTruthForComputation() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_SEEN).block();
- messageIdToImapUidDAO.insert(METADATA_UNSEEN).block();
+ RecomputeMailboxCountersService.Options options();
- testee.recomputeMailboxCounters(new Context()).block();
+ CassandraMessageIdDAO imapUidToMessageIdDAO();
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .contains(MailboxCounters.builder()
- .mailboxId(CASSANDRA_ID_1)
- .count(1)
- .unseen(1)
- .build());
- }
+ CassandraMessageIdToImapUidDAO messageIdToImapUidDAO();
- @Test
- void recomputeMailboxCountersShouldIgnoreMissingMailboxListReferences() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_SEEN).block();
+ CassandraMailboxCounterDAO counterDAO();
- testee.recomputeMailboxCounters(new Context()).block();
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenNoMailboxes() {
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .isEmpty();
- }
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenMailboxWithNoMessages() {
+ mailboxDAO().save(MAILBOX).block();
- @Test
- void recomputeMailboxCountersShouldIgnoreOrphanMailboxListReference() {
- mailboxDAO.save(MAILBOX).block();
- imapUidToMessageIdDAO.insert(METADATA_UNSEEN).block();
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
- testee.recomputeMailboxCounters(new Context()).block();
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenMailboxWithMessages() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+ counterDAO().incrementUnseenAndCount(CASSANDRA_ID_1).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
- assertThat(counterDAO.retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
- .isEmpty();
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenMessageDenormalizationIssue() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_SEEN).block();
+ counterDAO().incrementUnseenAndCount(CASSANDRA_ID_1).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldReturnCountersAreIncorrect() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenOrphanMailboxRegistration() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ counterDAO().incrementUnseenAndCount(CASSANDRA_ID_1).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldReturnCompletedWhenMailboxListReferenceIsMissing() {
+ mailboxDAO().save(MAILBOX).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+ counterDAO().incrementUnseenAndCount(CASSANDRA_ID_1).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(testee().recomputeMailboxCounters(new Context(), options()).block())
+ .isEqualTo(Result.COMPLETED);
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldNoopWhenMailboxWithoutMessage() {
+ mailboxDAO().save(MAILBOX).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .isEmpty();
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldNoopWhenValidCounters() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+ counterDAO().incrementUnseenAndCount(CASSANDRA_ID_1).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .contains(MailboxCounters.builder()
+ .mailboxId(CASSANDRA_ID_1)
+ .count(1)
+ .unseen(1)
+ .build());
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldRecreateMissingCounters() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .contains(MailboxCounters.builder()
+ .mailboxId(CASSANDRA_ID_1)
+ .count(1)
+ .unseen(1)
+ .build());
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldResetIncorrectCounters() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .contains(MailboxCounters.builder()
+ .mailboxId(CASSANDRA_ID_1)
+ .count(1)
+ .unseen(1)
+ .build());
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldTakeSeenIntoAccount() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_SEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_SEEN).block();
+ counterDAO().incrementCount(CASSANDRA_ID_1).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .contains(MailboxCounters.builder()
+ .mailboxId(CASSANDRA_ID_1)
+ .count(1)
+ .unseen(0)
+ .build());
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldUseSourceOfTruthForComputation() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_SEEN).block();
+ messageIdToImapUidDAO().insert(METADATA_UNSEEN).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .contains(MailboxCounters.builder()
+ .mailboxId(CASSANDRA_ID_1)
+ .count(1)
+ .unseen(1)
+ .build());
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldIgnoreMissingMailboxListReferences() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_SEEN).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .isEmpty();
+ }
+
+ @Test
+ default void recomputeMailboxCountersShouldIgnoreOrphanMailboxListReference() {
+ mailboxDAO().save(MAILBOX).block();
+ imapUidToMessageIdDAO().insert(METADATA_UNSEEN).block();
+
+ testee().recomputeMailboxCounters(new Context(), options()).block();
+
+ assertThat(counterDAO().retrieveMailboxCounters(CASSANDRA_ID_1).blockOptional())
+ .isEmpty();
+ }
}
}
\ No newline at end of file
diff --git a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskSerializationTest.java b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskSerializationTest.java
index 15c787c..e46fa08 100644
--- a/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskSerializationTest.java
+++ b/mailbox/cassandra/src/test/java/org/apache/james/mailbox/cassandra/mail/task/RecomputeMailboxCountersTaskSerializationTest.java
@@ -19,16 +19,14 @@
package org.apache.james.mailbox.cassandra.mail.task;
+import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import java.time.Instant;
-import java.util.UUID;
import org.apache.james.JsonSerializationVerifier;
-import org.apache.james.core.Username;
-import org.apache.james.mailbox.cassandra.ids.CassandraId;
-import org.apache.james.mailbox.model.MailboxConstants;
-import org.apache.james.mailbox.model.MailboxPath;
+import org.apache.james.json.JsonGenericSerializer;
+import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService.Options;
import org.junit.jupiter.api.Test;
import com.google.common.collect.ImmutableList;
@@ -38,8 +36,17 @@ class RecomputeMailboxCountersTaskSerializationTest {
private static final String MAILBOX_ID_AS_STRING = "464765a0-e4e7-11e4-aba4-710c1de3782b";
private static final RecomputeMailboxCountersService SERVICE = mock(RecomputeMailboxCountersService.class);
- private static final RecomputeMailboxCountersTask TASK = new RecomputeMailboxCountersTask(SERVICE);
- private static final String SERIALIZED_TASK = "{\"type\": \"recompute-mailbox-counters\"}";
+ private static final RecomputeMailboxCountersTask TASK_TRUSTED = new RecomputeMailboxCountersTask(SERVICE, Options.trustMessageDenormalization());
+ private static final RecomputeMailboxCountersTask TASK_UNTRUSTED = new RecomputeMailboxCountersTask(SERVICE, Options.recheckMessageDenormalization());
+ private static final String SERIALIZED_TASK_TRUSTED = "{" +
+ " \"type\": \"recompute-mailbox-counters\"," +
+ " \"trustMessageDenormalization\": true" +
+ "}";
+ private static final String SERIALIZED_TASK_UNTRUSTED = "{" +
+ " \"type\": \"recompute-mailbox-counters\"," +
+ " \"trustMessageDenormalization\": false" +
+ "}";
+ private static final String SERIALIZED_TASK_OLD = "{\"type\": \"recompute-mailbox-counters\"}";
private static final RecomputeMailboxCountersTask.Details DETAILS = new RecomputeMailboxCountersTask.Details(TIMESTAMP, 12, ImmutableList.of(MAILBOX_ID_AS_STRING));
private static final String SERIALIZED_ADDITIONAL_INFORMATION = "{" +
" \"type\":\"recompute-mailbox-counters\"," +
@@ -49,14 +56,33 @@ class RecomputeMailboxCountersTaskSerializationTest {
"}";
@Test
- void taskShouldBeSerializable() throws Exception {
+ void taskShouldBeSerializableWhenTrusted() throws Exception {
JsonSerializationVerifier.dtoModule(RecomputeMailboxCountersTaskDTO.module(SERVICE))
- .bean(TASK)
- .json(SERIALIZED_TASK)
+ .bean(TASK_TRUSTED)
+ .json(SERIALIZED_TASK_TRUSTED)
.verify();
}
@Test
+ void taskShouldBeSerializableWhenUnTrusted() throws Exception {
+ JsonSerializationVerifier.dtoModule(RecomputeMailboxCountersTaskDTO.module(SERVICE))
+ .bean(TASK_UNTRUSTED)
+ .json(SERIALIZED_TASK_UNTRUSTED)
+ .verify();
+ }
+
+ @Test
+ void taskWithoutTrustFieldShouldBeWellDeSerialized() throws Exception {
+ RecomputeMailboxCountersTask domainObject = JsonGenericSerializer
+ .forModules(RecomputeMailboxCountersTaskDTO.module(SERVICE))
+ .withoutNestedType()
+ .deserialize(SERIALIZED_TASK_OLD);
+
+ assertThat(domainObject)
+ .isEqualToComparingFieldByFieldRecursively(TASK_UNTRUSTED);
+ }
+
+ @Test
void additionalInformationShouldBeSerializable() throws Exception {
JsonSerializationVerifier.dtoModule(RecomputeMailboxCountersTaskAdditionalInformationDTO.MODULE)
.bean(DETAILS)
diff --git a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/RecomputeMailboxCountersRequestToTask.java b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/RecomputeMailboxCountersRequestToTask.java
index 2ec6679..2d60e61 100644
--- a/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/RecomputeMailboxCountersRequestToTask.java
+++ b/server/protocols/webadmin/webadmin-cassandra/src/main/java/org/apache/james/webadmin/routes/RecomputeMailboxCountersRequestToTask.java
@@ -22,6 +22,7 @@ package org.apache.james.webadmin.routes;
import javax.inject.Inject;
import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService;
+import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersService.Options;
import org.apache.james.mailbox.cassandra.mail.task.RecomputeMailboxCountersTask;
import org.apache.james.webadmin.tasks.TaskFromRequestRegistry;
import org.apache.james.webadmin.tasks.TaskRegistrationKey;
@@ -32,6 +33,6 @@ public class RecomputeMailboxCountersRequestToTask extends TaskFromRequestRegist
@Inject
public RecomputeMailboxCountersRequestToTask(RecomputeMailboxCountersService service) {
super(REGISTRATION_KEY,
- request -> new RecomputeMailboxCountersTask(service));
+ request -> new RecomputeMailboxCountersTask(service, Options.recheckMessageDenormalization()));
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org