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 2019/03/26 04:39:35 UTC

[james-project] 04/10: MAILBOX-385 Rework DeletedMessageZipperTest

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 0d6b733b88c1509baa966ca0143a010e9510183a
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Fri Mar 22 11:33:23 2019 +0700

    MAILBOX-385 Rework DeletedMessageZipperTest
    
     - Do not extract the method being asserted
     - Indent following the given/when/then pattern
     - Avoid relying on complex capture logic - prefer spies that are easier to use
     - Avoid using assertThatThrowBy for ignoring exception - reserve it for assertions
    
    We put a big deal to allow a method-by-method reviewable diff.
---
 .../james/vault/DeletedMessageZipperTest.java      | 184 +++++++++------------
 1 file changed, 81 insertions(+), 103 deletions(-)

diff --git a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageZipperTest.java b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageZipperTest.java
index 6614eaf..9ae108f 100644
--- a/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageZipperTest.java
+++ b/mailbox/plugin/deleted-messages-vault/src/test/java/org/apache/james/vault/DeletedMessageZipperTest.java
@@ -31,19 +31,21 @@ import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatCode;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
+import java.util.Collection;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Stream;
 
 import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
@@ -53,45 +55,12 @@ import org.apache.james.mailbox.backup.MessageIdExtraField;
 import org.apache.james.mailbox.backup.SizeExtraField;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import com.github.fge.lambdas.Throwing;
 
-import reactor.core.publisher.Mono;
-
 class DeletedMessageZipperTest {
-
-    private class ZipArchiveStreamCaptor implements Answer<ZipArchiveOutputStream> {
-
-        ZipArchiveOutputStream captured;
-
-        @Override
-        public ZipArchiveOutputStream answer(InvocationOnMock invocation) throws Throwable {
-            ZipArchiveOutputStream zipArchiveOutputStream = (ZipArchiveOutputStream) invocation.callRealMethod();
-            captured = spy(zipArchiveOutputStream);
-            return captured;
-        }
-    }
-
-    private class LoadedResourcesStreamCaptor implements Answer<Optional<DeletedMessageWithContent>> {
-
-        List<DeletedMessageWithContent> captured = new ArrayList<>();
-
-        @Override
-        public Optional<DeletedMessageWithContent> answer(InvocationOnMock invocation) throws Throwable {
-            Optional<DeletedMessageWithContent> messageWithContent = (Optional<DeletedMessageWithContent>) invocation.callRealMethod();
-            return messageWithContent.map(this::returnSpied);
-        }
-
-        private DeletedMessageWithContent returnSpied(DeletedMessageWithContent message) {
-            DeletedMessageWithContent spied = spy(message);
-            captured.add(spied);
-            return spied;
-        }
-    }
-
-    private static final DeletedMessageContentLoader CONTENT_LOADER = message -> Mono.just(new ByteArrayInputStream(CONTENT));
+    private static final DeletedMessageContentLoader CONTENT_LOADER = message -> new ByteArrayInputStream(CONTENT);
     private static final String MESSAGE_CONTENT = new String(CONTENT, StandardCharsets.UTF_8);
     private DeletedMessageZipper zipper;
 
@@ -102,8 +71,11 @@ class DeletedMessageZipperTest {
 
     @Test
     void zipShouldPutEntriesToOutputStream() throws Exception {
-        ByteArrayOutputStream messageContents = zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2));
-        try (ZipFile zipFile = zipFile(messageContents)) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), outputStream);
+
+        try (ZipFile zipFile = zipFile(outputStream)) {
             assertThatZip(zipFile)
                 .containsOnlyEntriesMatching(
                     hasName(MESSAGE_ID.serialize()).hasStringContent(MESSAGE_CONTENT),
@@ -113,8 +85,11 @@ class DeletedMessageZipperTest {
 
     @Test
     void zipShouldPutExtraFields() throws Exception {
-        ByteArrayOutputStream messageContents = zip(Stream.of(DELETED_MESSAGE));
-        try (ZipFile zipFile = zipFile(messageContents)) {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+        zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE), outputStream);
+
+        try (ZipFile zipFile = zipFile(outputStream)) {
             assertThatZip(zipFile)
                 .containsOnlyEntriesMatching(
                     hasName(MESSAGE_ID.serialize())
@@ -133,109 +108,112 @@ class DeletedMessageZipperTest {
 
     @Test
     void zipShouldCloseAllResourcesStreamWhenFinishZipping() throws Exception {
-        LoadedResourcesStreamCaptor captor = new LoadedResourcesStreamCaptor();
-        doAnswer(captor)
-            .when(zipper).messageWithContent(any(), any());
+        Collection<InputStream> loadedContents = new ConcurrentLinkedQueue<>();
 
-        zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2));
+        zipper.zip(spyLoadedContents(loadedContents), Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream());
 
-        List<DeletedMessageWithContent> loadedResources = captor.captured;
-        assertThat(loadedResources)
-            .hasSize(2);
-        loadedResources.stream()
-            .forEach(Throwing.consumer(spiedMessage -> verify(spiedMessage, times(1)).close()));
+        assertThat(loadedContents)
+            .hasSize(2)
+            .allSatisfy(Throwing.consumer(content -> verify(content, times(1)).close()));
     }
 
     @Test
     void zipShouldTerminateZipArchiveStreamWhenFinishZipping() throws Exception {
-        ZipArchiveStreamCaptor captor = new ZipArchiveStreamCaptor();
-        doAnswer(captor)
-            .when(zipper).newZipArchiveOutputStream(any());
+        AtomicReference<ZipArchiveOutputStream> zipOutputStreamReference = new AtomicReference<>();
+        when(zipper.newZipArchiveOutputStream(any())).thenAnswer(spyZipOutPutStream(zipOutputStreamReference));
 
-        zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2));
+        zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream());
 
-        ZipArchiveOutputStream captured = captor.captured;
-        verify(captured, times(1)).finish();
-        verify(captured, times(1)).close();
+        verify(zipOutputStreamReference.get(), times(1)).finish();
+        verify(zipOutputStreamReference.get(), times(1)).close();
     }
 
     @Test
     void zipShouldThrowWhenCreateEntryGetException() throws Exception {
-        doThrow(new IOException("mocked exception"))
-            .when(zipper).createEntry(any(), any());
+        doThrow(new IOException("mocked exception")).when(zipper).createEntry(any(), any());
 
-        assertThatThrownBy(() -> zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2)))
+        assertThatThrownBy(() -> zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream()))
             .isInstanceOf(IOException.class);
     }
 
     @Test
     void zipShouldThrowWhenPutMessageToEntryGetException() throws Exception {
-        doThrow(new IOException("mocked exception"))
-            .when(zipper).putMessageToEntry(any(), any());
+        doThrow(new IOException("mocked exception")).when(zipper).putMessageToEntry(any(), any(), any());
 
-        assertThatThrownBy(() -> zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2)))
+        assertThatThrownBy(() -> zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream()))
             .isInstanceOf(IOException.class);
     }
 
     @Test
     void zipShouldStopLoadingResourcesWhenGettingException() throws Exception {
-        doThrow(new IOException("mocked exception"))
-            .when(zipper).createEntry(any(), any());
-
-        LoadedResourcesStreamCaptor captor = new LoadedResourcesStreamCaptor();
-        doAnswer(captor)
-            .when(zipper).messageWithContent(any(), any());
-
-        assertThatThrownBy(() -> zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2)))
-            .isInstanceOf(IOException.class);
+        doThrow(new IOException("mocked exception")).when(zipper).createEntry(any(), any());
+        DeletedMessageContentLoader contentLoader = spy(new DeletedMessageContentLoader() {
+            // lambdas are final and thus can't be spied
+            @Override
+            public InputStream load(DeletedMessage deletedMessage) {
+                return new ByteArrayInputStream(CONTENT);
+            }
+        });
+
+        try {
+            zipper.zip(contentLoader, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream());
+        } catch (Exception e) {
+            // ignored
+        }
 
-        List<DeletedMessageWithContent> loadedResources = captor.captured;
-        assertThat(loadedResources)
-            .hasSize(1);
-        loadedResources.stream()
-            .forEach(Throwing.consumer(spiedMessage -> verify(spiedMessage, times(1)).close()));
+        verify(contentLoader, times(1)).load(any());
     }
 
     @Test
     void zipShouldCloseParameterOutputStreamWhenGettingException() throws Exception {
-        doThrow(new IOException("mocked exception"))
-            .when(zipper).putMessageToEntry(any(), any());
-
+        doThrow(new IOException("mocked exception")).when(zipper).putMessageToEntry(any(), any(), any());
         ByteArrayOutputStream outputStream = spy(new ByteArrayOutputStream());
-        assertThatThrownBy(() -> zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE), outputStream))
-            .isInstanceOf(IOException.class);
+
+        try {
+            zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE), outputStream);
+        } catch (Exception e) {
+            // ignored
+        }
 
         verify(outputStream, times(1)).close();
     }
 
     @Test
     void zipShouldTerminateZipArchiveStreamWhenGettingException() throws Exception {
-        doThrow(new IOException("mocked exception"))
-            .when(zipper).putMessageToEntry(any(), any());
-
-        ZipArchiveStreamCaptor captor = new ZipArchiveStreamCaptor();
-        doAnswer(captor)
-            .when(zipper).newZipArchiveOutputStream(any());
-
-        assertThatThrownBy(() -> zip(Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2)))
-            .isInstanceOf(IOException.class);
+        doThrow(new IOException("mocked exception")).when(zipper).putMessageToEntry(any(), any(), any());
+        AtomicReference<ZipArchiveOutputStream> zipOutputStreamReference = new AtomicReference<>();
+        when(zipper.newZipArchiveOutputStream(any())).thenAnswer(spyZipOutPutStream(zipOutputStreamReference));
+
+        try {
+            zipper.zip(CONTENT_LOADER, Stream.of(DELETED_MESSAGE, DELETED_MESSAGE_2), new ByteArrayOutputStream());
+        } catch (Exception e) {
+            // ignored
+        }
 
-        ZipArchiveOutputStream captured = captor.captured;
-        verify(captured, times(1)).finish();
-        verify(captured, times(1)).close();
+        verify(zipOutputStreamReference.get(), times(1)).finish();
+        verify(zipOutputStreamReference.get(), times(1)).close();
     }
 
-    private ByteArrayOutputStream zip(Stream<DeletedMessage> deletedMessages, DeletedMessageZipper zipper) throws IOException {
-        ByteArrayOutputStream zipOutputStream = new ByteArrayOutputStream();
-        zipper.zip(CONTENT_LOADER, deletedMessages, zipOutputStream);
-        return zipOutputStream;
+    private ZipFile zipFile(ByteArrayOutputStream output) throws IOException {
+        return new ZipFile(new SeekableInMemoryByteChannel(output.toByteArray()));
     }
 
-    private ByteArrayOutputStream zip(Stream<DeletedMessage> deletedMessages) throws IOException {
-        return zip(deletedMessages, zipper);
+    private DeletedMessageZipper.DeletedMessageContentLoader spyLoadedContents(Collection<InputStream> loadedContents) {
+        Answer<InputStream> spyedContent = invocationOnMock -> {
+            InputStream result = spy(new ByteArrayInputStream(CONTENT));
+            loadedContents.add(result);
+            return result;
+        };
+        DeletedMessageContentLoader contentLoader = mock(DeletedMessageContentLoader.class);
+        when(contentLoader.load(any())).thenAnswer(spyedContent);
+        return contentLoader;
     }
 
-    private ZipFile zipFile(ByteArrayOutputStream output) throws IOException {
-        return new ZipFile(new SeekableInMemoryByteChannel(output.toByteArray()));
+    private Answer<ZipArchiveOutputStream> spyZipOutPutStream(AtomicReference<ZipArchiveOutputStream> spiedZipArchiveOutputStream) {
+        return invocation -> {
+            ZipArchiveOutputStream zipArchiveOutputStream = spy((ZipArchiveOutputStream) invocation.callRealMethod());
+            spiedZipArchiveOutputStream.set(zipArchiveOutputStream);
+            return zipArchiveOutputStream;
+        };
     }
 }
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org