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 6f92767ee5277b597a3bfd75fbc25e6e39fe44fa Author: Benoit Tellier <btell...@linagora.com> AuthorDate: Mon Dec 16 14:38:31 2019 +0700 JAMES-2993 Implement recompute all JMAP message preview task --- .../MemoryMessageFastViewProjection.java | 7 +- .../protocols/webadmin/webadmin-data-jmap/pom.xml | 71 +++++++++ .../jmap/MessageFastViewProjectionCorrector.java | 142 +++++++++++++++++ .../data/jmap/RecomputeAllPreviewsTask.java | 168 +++++++++++++++++++++ ...uteAllPreviewsTaskAdditionalInformationDTO.java | 98 ++++++++++++ ...llPreviewsTaskAdditionalInformationDTOTest.java | 47 ++++++ .../RecomputeAllPreviewsTaskSerializationTest.java | 53 +++++++ .../json/recomputeAll.additionalInformation.json | 8 + .../src/test/resources/json/recomputeAll.task.json | 1 + 9 files changed, 591 insertions(+), 4 deletions(-) diff --git a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java index 9492ab3..e39fcbe 100644 --- a/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java +++ b/server/data/data-jmap/src/main/java/org/apache/james/jmap/memory/projections/MemoryMessageFastViewProjection.java @@ -28,7 +28,6 @@ import org.apache.james.jmap.api.projections.MessageFastViewProjection; import org.apache.james.mailbox.model.MessageId; import org.apache.james.metrics.api.Metric; import org.apache.james.metrics.api.MetricFactory; -import org.reactivestreams.Publisher; import com.google.common.base.Preconditions; @@ -48,7 +47,7 @@ public class MemoryMessageFastViewProjection implements MessageFastViewProjectio } @Override - public Publisher<Void> store(MessageId messageId, MessageFastViewPrecomputedProperties precomputedProperties) { + public Mono<Void> store(MessageId messageId, MessageFastViewPrecomputedProperties precomputedProperties) { Preconditions.checkNotNull(messageId); Preconditions.checkNotNull(precomputedProperties); @@ -56,7 +55,7 @@ public class MemoryMessageFastViewProjection implements MessageFastViewProjectio } @Override - public Publisher<MessageFastViewPrecomputedProperties> retrieve(MessageId messageId) { + public Mono<MessageFastViewPrecomputedProperties> retrieve(MessageId messageId) { Preconditions.checkNotNull(messageId); return Mono.fromSupplier(() -> previews.get(messageId)) @@ -65,7 +64,7 @@ public class MemoryMessageFastViewProjection implements MessageFastViewProjectio } @Override - public Publisher<Void> delete(MessageId messageId) { + public Mono<Void> delete(MessageId messageId) { Preconditions.checkNotNull(messageId); return Mono.fromRunnable(() -> previews.remove(messageId)); diff --git a/server/protocols/webadmin/webadmin-data-jmap/pom.xml b/server/protocols/webadmin/webadmin-data-jmap/pom.xml index 9ac8a75..e42b17e 100644 --- a/server/protocols/webadmin/webadmin-data-jmap/pom.xml +++ b/server/protocols/webadmin/webadmin-data-jmap/pom.xml @@ -33,15 +33,86 @@ <dependencies> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-api</artifactId> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-api</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>apache-james-mailbox-memory</artifactId> + <type>test-jar</type> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-json</artifactId> + <scope>test</scope> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>james-server-data-jmap</artifactId> </dependency> <dependency> <groupId>${project.groupId}</groupId> + <artifactId>james-server-data-api</artifactId> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-server-data-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${project.groupId}</groupId> <artifactId>james-server-jmap-draft</artifactId> </dependency> <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>james-server-task-json</artifactId> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-server-task-memory</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-server-webadmin-core</artifactId> + </dependency> + <dependency> <groupId>${james.groupId}</groupId> <artifactId>james-server-webadmin-core</artifactId> + <scope>test</scope> + <type>test-jar</type> + </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>testing-base</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>io.rest-assured</groupId> + <artifactId>rest-assured</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>net.javacrumbs.json-unit</groupId> + <artifactId>json-unit-assertj</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.mockito</groupId> + <artifactId>mockito-core</artifactId> + <scope>test</scope> </dependency> </dependencies> </project> \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java new file mode 100644 index 0000000..6fc4c86 --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/MessageFastViewProjectionCorrector.java @@ -0,0 +1,142 @@ +/**************************************************************** + * 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.data.jmap; + +import java.util.concurrent.atomic.AtomicLong; + +import javax.inject.Inject; + +import org.apache.commons.lang3.tuple.Pair; +import org.apache.james.core.Username; +import org.apache.james.jmap.api.projections.MessageFastViewPrecomputedProperties; +import org.apache.james.jmap.api.projections.MessageFastViewProjection; +import org.apache.james.mailbox.MailboxManager; +import org.apache.james.mailbox.MailboxSession; +import org.apache.james.mailbox.MessageManager; +import org.apache.james.mailbox.exception.MailboxException; +import org.apache.james.mailbox.model.FetchGroup; +import org.apache.james.mailbox.model.MessageRange; +import org.apache.james.mailbox.model.search.MailboxQuery; +import org.apache.james.user.api.UsersRepository; +import org.apache.james.user.api.UsersRepositoryException; +import org.apache.james.util.streams.Iterators; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.github.fge.lambdas.Throwing; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +public class MessageFastViewProjectionCorrector { + + private static final Logger LOGGER = LoggerFactory.getLogger(MessageFastViewProjectionCorrector.class); + + static class Progress { + private final AtomicLong processedUserCount; + private final AtomicLong processedMessageCount; + private final AtomicLong failedUserCount; + private final AtomicLong failedMessageCount; + + Progress() { + failedUserCount = new AtomicLong(); + processedMessageCount = new AtomicLong(); + processedUserCount = new AtomicLong(); + failedMessageCount = new AtomicLong(); + } + + long getProcessedUserCount() { + return processedUserCount.get(); + } + + long getProcessedMessageCount() { + return processedMessageCount.get(); + } + + long getFailedUserCount() { + return failedUserCount.get(); + } + + long getFailedMessageCount() { + return failedMessageCount.get(); + } + + boolean failed() { + return failedMessageCount.get() > 0 || failedUserCount.get() > 0; + } + } + + private final UsersRepository usersRepository; + private final MailboxManager mailboxManager; + private final MessageFastViewProjection messageFastViewProjection; + private final MessageFastViewPrecomputedProperties.Factory projectionItemFactory; + + @Inject + MessageFastViewProjectionCorrector(UsersRepository usersRepository, MailboxManager mailboxManager, + MessageFastViewProjection messageFastViewProjection, + MessageFastViewPrecomputedProperties.Factory projectionItemFactory) { + this.usersRepository = usersRepository; + this.mailboxManager = mailboxManager; + this.messageFastViewProjection = messageFastViewProjection; + this.projectionItemFactory = projectionItemFactory; + } + + Mono<Void> correctAllProjectionItems(Progress progress) { + try { + return Iterators.toFlux(usersRepository.list()) + .concatMap(username -> correctUsersProjectionItems(progress, username)) + .then(); + } catch (UsersRepositoryException e) { + return Mono.error(e); + } + } + + private Mono<Void> correctUsersProjectionItems(Progress progress, Username username) { + try { + MailboxSession session = mailboxManager.createSystemSession(username); + return Flux.fromIterable(mailboxManager.search(MailboxQuery.privateMailboxesBuilder(session).build(), session)) + .concatMap(mailboxMetadata -> Mono.fromCallable(() -> mailboxManager.getMailbox(mailboxMetadata.getId(), session))) + .concatMap(Throwing.function(messageManager -> correctMailboxProjectionItems(progress, messageManager, session))) + .doOnComplete(progress.processedUserCount::incrementAndGet) + .onErrorContinue((error, o) -> { + LOGGER.error("JMAP preview re-computation aborted for {}", username, error); + progress.failedUserCount.incrementAndGet(); + }) + .then(); + } catch (MailboxException e) { + LOGGER.error("JMAP preview re-computation aborted for {} as we failed listing user mailboxes", username, e); + progress.failedUserCount.incrementAndGet(); + return Mono.empty(); + } + } + + private Mono<Void> correctMailboxProjectionItems(Progress progress, MessageManager messageManager, MailboxSession session) throws MailboxException { + return Iterators.toFlux(messageManager.getMessages(MessageRange.all(), FetchGroup.MINIMAL, session)) + .concatMap(Throwing.function(messageResult -> Iterators.toFlux(messageManager.getMessages(MessageRange.all(), FetchGroup.BODY_CONTENT, session)))) + .map(Throwing.function(messageResult -> Pair.of(messageResult.getMessageId(), projectionItemFactory.from(messageResult)))) + .concatMap(pair -> Mono.from(messageFastViewProjection.store(pair.getKey(), pair.getValue())) + .doOnSuccess(any -> progress.processedMessageCount.incrementAndGet())) + .onErrorContinue((error, triggeringValue) -> { + LOGGER.error("JMAP preview re-computation aborted for {} - {}", session.getUser(), triggeringValue, error); + progress.failedMessageCount.incrementAndGet(); + }) + .then(); + } +} diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java new file mode 100644 index 0000000..bacf8ad --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTask.java @@ -0,0 +1,168 @@ +/**************************************************************** + * 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.data.jmap; + +import java.time.Clock; +import java.time.Instant; +import java.util.Objects; +import java.util.Optional; + +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 RecomputeAllPreviewsTask implements Task { + static final TaskType TASK_TYPE = TaskType.of("RecomputeAllPreviewsTask"); + + public static class AdditionalInformation implements TaskExecutionDetails.AdditionalInformation { + private static AdditionalInformation from(MessageFastViewProjectionCorrector.Progress progress) { + return new AdditionalInformation( + progress.getProcessedUserCount(), + progress.getProcessedMessageCount(), + progress.getFailedUserCount(), + progress.getFailedMessageCount(), + Clock.systemUTC().instant()); + } + + private final long processedUserCount; + private final long processedMessageCount; + private final long failedUserCount; + private final long failedMessageCount; + private final Instant timestamp; + + public AdditionalInformation(long processedUserCount, long processedMessageCount, long failedUserCount, long failedMessageCount, Instant timestamp) { + this.processedUserCount = processedUserCount; + this.processedMessageCount = processedMessageCount; + this.failedUserCount = failedUserCount; + this.failedMessageCount = failedMessageCount; + this.timestamp = timestamp; + } + + public long getProcessedUserCount() { + return processedUserCount; + } + + public long getProcessedMessageCount() { + return processedMessageCount; + } + + public long getFailedUserCount() { + return failedUserCount; + } + + public long getFailedMessageCount() { + return failedMessageCount; + } + + @Override + public Instant timestamp() { + return timestamp; + } + + @Override + public final boolean equals(Object o) { + if (o instanceof AdditionalInformation) { + AdditionalInformation that = (AdditionalInformation) o; + + return Objects.equals(this.processedUserCount, that.processedUserCount) + && Objects.equals(this.processedMessageCount, that.processedMessageCount) + && Objects.equals(this.failedUserCount, that.failedUserCount) + && Objects.equals(this.failedMessageCount, that.failedMessageCount) + && Objects.equals(this.timestamp, that.timestamp); + } + return false; + } + + @Override + public final int hashCode() { + return Objects.hash(processedUserCount, processedMessageCount, failedUserCount, failedMessageCount, timestamp); + } + } + + public static class RecomputeAllPreviousTaskDTO implements TaskDTO { + private final String type; + + public RecomputeAllPreviousTaskDTO(@JsonProperty("type") String type) { + this.type = type; + } + + @Override + public String getType() { + return type; + } + } + + public static TaskDTOModule<RecomputeAllPreviewsTask, RecomputeAllPreviousTaskDTO> module(MessageFastViewProjectionCorrector corrector) { + return DTOModule + .forDomainObject(RecomputeAllPreviewsTask.class) + .convertToDTO(RecomputeAllPreviousTaskDTO.class) + .toDomainObjectConverter(dto -> new RecomputeAllPreviewsTask(corrector)) + .toDTOConverter((task, type) -> new RecomputeAllPreviousTaskDTO(type)) + .typeName(TASK_TYPE.asString()) + .withFactory(TaskDTOModule::new); + } + + private final MessageFastViewProjectionCorrector corrector; + private final MessageFastViewProjectionCorrector.Progress progress; + + RecomputeAllPreviewsTask(MessageFastViewProjectionCorrector corrector) { + this.corrector = corrector; + this.progress = new MessageFastViewProjectionCorrector.Progress(); + } + + @Override + public Result run() { + corrector.correctAllProjectionItems(progress) + .subscribeOn(Schedulers.boundedElastic()) + .block(); + + if (progress.failed()) { + return Result.PARTIAL; + } + return Result.COMPLETED; + } + + @Override + public TaskType type() { + return TASK_TYPE; + } + + @Override + public Optional<TaskExecutionDetails.AdditionalInformation> details() { + return Optional.of(AdditionalInformation.from(progress)); + } + + @Override + public final boolean equals(Object o) { + return o instanceof RecomputeAllPreviewsTask; + } + + @Override + public final int hashCode() { + return Objects.hash(RecomputeAllPreviewsTask.class); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java new file mode 100644 index 0000000..aab6aa7 --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/main/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTO.java @@ -0,0 +1,98 @@ +/**************************************************************** + * 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.data.jmap; + +import java.time.Instant; + +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; +import com.google.common.annotations.VisibleForTesting; + +public class RecomputeAllPreviewsTaskAdditionalInformationDTO implements AdditionalInformationDTO { + public static final AdditionalInformationDTOModule<RecomputeAllPreviewsTask.AdditionalInformation, RecomputeAllPreviewsTaskAdditionalInformationDTO> SERIALIZATION_MODULE = + DTOModule.forDomainObject(RecomputeAllPreviewsTask.AdditionalInformation.class) + .convertToDTO(RecomputeAllPreviewsTaskAdditionalInformationDTO.class) + .toDomainObjectConverter(dto -> new RecomputeAllPreviewsTask.AdditionalInformation( + dto.getProcessedUserCount(), + dto.getProcessedMessageCount(), + dto.getFailedUserCount(), + dto.getFailedMessageCount(), + dto.timestamp)) + .toDTOConverter((details, type) -> new RecomputeAllPreviewsTaskAdditionalInformationDTO( + type, + details.timestamp(), + details.getProcessedUserCount(), + details.getProcessedMessageCount(), + details.getFailedUserCount(), + details.getFailedMessageCount())) + .typeName(RecomputeAllPreviewsTask.TASK_TYPE.asString()) + .withFactory(AdditionalInformationDTOModule::new); + + private final String type; + private final Instant timestamp; + private final long processedUserCount; + private final long processedMessageCount; + private final long failedUserCount; + private final long failedMessageCount; + + @VisibleForTesting + RecomputeAllPreviewsTaskAdditionalInformationDTO(@JsonProperty("type") String type, + @JsonProperty("timestamp") Instant timestamp, + @JsonProperty("processedUserCount") long processedUserCount, + @JsonProperty("processedMessageCount") long processedMessageCount, + @JsonProperty("failedUserCount") long failedUserCount, + @JsonProperty("failedMessageCount") long failedMessageCount) { + this.type = type; + this.timestamp = timestamp; + this.processedUserCount = processedUserCount; + this.processedMessageCount = processedMessageCount; + this.failedUserCount = failedUserCount; + this.failedMessageCount = failedMessageCount; + } + + @Override + public String getType() { + return type; + } + + @Override + public Instant getTimestamp() { + return timestamp; + } + + public long getProcessedUserCount() { + return processedUserCount; + } + + public long getProcessedMessageCount() { + return processedMessageCount; + } + + public long getFailedUserCount() { + return failedUserCount; + } + + public long getFailedMessageCount() { + return failedMessageCount; + } +} diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java new file mode 100644 index 0000000..125464f --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskAdditionalInformationDTOTest.java @@ -0,0 +1,47 @@ +/**************************************************************** + * 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.data.jmap; + +import java.time.Instant; + +import org.apache.james.JsonSerializationVerifier; +import org.apache.james.util.ClassLoaderUtils; +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class RecomputeAllPreviewsTaskAdditionalInformationDTOTest { + private static final Instant INSTANT = Instant.parse("2007-12-03T10:15:30.00Z"); + private static final RecomputeAllPreviewsTask.AdditionalInformation DOMAIN_OBJECT = new RecomputeAllPreviewsTask.AdditionalInformation(1, 2, 3, 4, INSTANT); + + @Test + void shouldMatchJsonSerializationContract() throws Exception { + JsonSerializationVerifier.dtoModule(RecomputeAllPreviewsTaskAdditionalInformationDTO.SERIALIZATION_MODULE) + .bean(DOMAIN_OBJECT) + .json(ClassLoaderUtils.getSystemResourceAsString("json/recomputeAll.additionalInformation.json")) + .verify(); + } + + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(RecomputeAllPreviewsTask.AdditionalInformation.class) + .verify(); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java new file mode 100644 index 0000000..e56432a --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/test/java/org/apache/james/webadmin/data/jmap/RecomputeAllPreviewsTaskSerializationTest.java @@ -0,0 +1,53 @@ +/**************************************************************** + * 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.data.jmap; + +import static org.mockito.Mockito.mock; + +import org.apache.james.JsonSerializationVerifier; +import org.apache.james.util.ClassLoaderUtils; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import nl.jqno.equalsverifier.EqualsVerifier; + +class RecomputeAllPreviewsTaskSerializationTest { + MessageFastViewProjectionCorrector corrector; + + @BeforeEach + void setUp() { + corrector = mock(MessageFastViewProjectionCorrector.class); + } + + @Test + void shouldMatchJsonSerializationContract() throws Exception { + JsonSerializationVerifier.dtoModule(RecomputeAllPreviewsTask.module(corrector)) + .bean(new RecomputeAllPreviewsTask(corrector)) + .json(ClassLoaderUtils.getSystemResourceAsString("json/recomputeAll.task.json")) + .verify(); + } + + @Test + void shouldMatchBeanContract() { + EqualsVerifier.forClass(RecomputeAllPreviewsTask.class) + .withIgnoredFields("corrector", "progress") + .verify(); + } +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json new file mode 100644 index 0000000..bc3d81f --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.additionalInformation.json @@ -0,0 +1,8 @@ +{ + "type":"RecomputeAllPreviewsTask", + "timestamp":"2007-12-03T10:15:30Z", + "processedUserCount":1, + "processedMessageCount":2, + "failedUserCount":3, + "failedMessageCount":4 +} \ No newline at end of file diff --git a/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json new file mode 100644 index 0000000..a447293 --- /dev/null +++ b/server/protocols/webadmin/webadmin-data-jmap/src/test/resources/json/recomputeAll.task.json @@ -0,0 +1 @@ +{"type":"RecomputeAllPreviewsTask"} \ 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