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/07/24 10:34:34 UTC

[james-project] 03/07: JAMES-3314 Mutualize CassandraBlobStoreContract

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 700116f79c8cc5f71279210142161719c0302152
Author: Benoit Tellier <bt...@linagora.com>
AuthorDate: Wed Jul 22 11:48:49 2020 +0700

    JAMES-3314 Mutualize CassandraBlobStoreContract
---
 ...reTest.java => CassandraBlobStoreContract.java} | 84 ++++++---------------
 .../blob/cassandra/CassandraBlobStoreTest.java     | 88 +---------------------
 .../CassandraPassTroughBlobStoreTest.java          | 87 +--------------------
 3 files changed, 29 insertions(+), 230 deletions(-)

diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreContract.java
similarity index 50%
copy from server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java
copy to server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreContract.java
index ae9136b..b6a6434 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreContract.java
@@ -22,7 +22,6 @@ package org.apache.james.blob.cassandra;
 import static org.apache.james.blob.api.BlobStore.StoragePolicy.LOW_COST;
 import static org.assertj.core.api.Assertions.assertThat;
 import static org.assertj.core.api.Assertions.assertThatThrownBy;
-import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import java.io.IOException;
@@ -30,21 +29,11 @@ import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.james.backends.cassandra.CassandraCluster;
-import org.apache.james.backends.cassandra.CassandraClusterExtension;
-import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
 import org.apache.james.blob.api.BlobId;
-import org.apache.james.blob.api.BlobStore;
-import org.apache.james.blob.api.BucketName;
-import org.apache.james.blob.api.HashBlobId;
-import org.apache.james.blob.api.MetricableBlobStore;
 import org.apache.james.blob.api.MetricableBlobStoreContract;
 import org.apache.james.blob.api.ObjectStoreException;
-import org.apache.james.server.blob.deduplication.BlobStoreFactory;
 import org.apache.james.util.io.ZeroedInputStream;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.RegisterExtension;
 
 import com.google.common.base.Strings;
 import com.google.common.hash.Hashing;
@@ -52,93 +41,62 @@ import com.google.common.hash.HashingInputStream;
 
 import reactor.core.publisher.Mono;
 
-public class CassandraBlobStoreTest implements MetricableBlobStoreContract {
-    private static final int CHUNK_SIZE = 10240;
-    private static final int MULTIPLE_CHUNK_SIZE = 3;
-
-    @RegisterExtension
-    static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraBlobModule.MODULE);
-
-    private BlobStore testee;
-    private CassandraDefaultBucketDAO defaultBucketDAO;
-
-    @BeforeEach
-    void setUp(CassandraCluster cassandra) {
-        HashBlobId.Factory blobIdFactory = new HashBlobId.Factory();
-        CassandraBucketDAO bucketDAO = new CassandraBucketDAO(blobIdFactory, cassandra.getConf());
-        defaultBucketDAO = spy(new CassandraDefaultBucketDAO(cassandra.getConf()));
-        CassandraConfiguration cassandraConfiguration = CassandraConfiguration.builder()
-            .blobPartSize(CHUNK_SIZE)
-            .build();
-        testee = new MetricableBlobStore(
-            metricsTestExtension.getMetricFactory(),
-            BlobStoreFactory.builder()
-                .dumbBlobStore(new CassandraDumbBlobStore(defaultBucketDAO, bucketDAO, cassandraConfiguration, BucketName.DEFAULT))
-                .blobIdFactory(blobIdFactory)
-                .defaultBucketName()
-                .deduplication());
-    }
-
-    @Override
-    public BlobStore testee() {
-        return testee;
-    }
+public interface CassandraBlobStoreContract extends MetricableBlobStoreContract {
+    int MULTIPLE_CHUNK_SIZE = 3;
+    int CHUNK_SIZE = 10240;
 
-    @Override
-    public BlobId.Factory blobIdFactory() {
-        return new HashBlobId.Factory();
-    }
+    CassandraDefaultBucketDAO defaultBucketDAO();
 
     @Test
-    void readBytesShouldReturnSplitSavedDataByChunk() {
+    default void readBytesShouldReturnSplitSavedDataByChunk() {
         String longString = Strings.repeat("0123456789\n", MULTIPLE_CHUNK_SIZE);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
+        BlobId blobId = Mono.from(testee().save(testee().getDefaultBucketName(), longString, LOW_COST)).block();
 
-        byte[] bytes = Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block();
+        byte[] bytes = Mono.from(testee().readBytes(testee().getDefaultBucketName(), blobId)).block();
 
         assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(longString);
     }
 
     @Test
-    void readBytesShouldNotReturnInvalidResultsWhenPartialDataPresent() {
+    default void readBytesShouldNotReturnInvalidResultsWhenPartialDataPresent() {
         int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
         String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
+        BlobId blobId = Mono.from(testee().save(testee().getDefaultBucketName(), longString, LOW_COST)).block();
 
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
+        when(defaultBucketDAO().readPart(blobId, 1)).thenReturn(Mono.empty());
 
-        assertThatThrownBy(() -> Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block())
+        assertThatThrownBy(() -> Mono.from(testee().readBytes(testee().getDefaultBucketName(), blobId)).block())
             .isInstanceOf(ObjectStoreException.class)
             .hasMessageContaining("Missing blob part for blobId");
     }
 
     @Test
-    void readShouldNotReturnInvalidResultsWhenPartialDataPresent() {
+    default void readShouldNotReturnInvalidResultsWhenPartialDataPresent() {
         int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
         String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
+        BlobId blobId = Mono.from(testee().save(testee().getDefaultBucketName(), longString, LOW_COST)).block();
 
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
+        when(defaultBucketDAO().readPart(blobId, 1)).thenReturn(Mono.empty());
 
-        assertThatThrownBy(() -> IOUtils.toString(testee.read(testee.getDefaultBucketName(), blobId), StandardCharsets.UTF_8))
+        assertThatThrownBy(() -> IOUtils.toString(testee().read(testee().getDefaultBucketName(), blobId), StandardCharsets.UTF_8))
             .isInstanceOf(ObjectStoreException.class)
             .hasMessageContaining("Missing blob part for blobId");
     }
 
     @Test
-    void deleteBucketShouldThrowWhenDeletingDefaultBucket() {
-        assertThatThrownBy(() ->  testee.deleteBucket(testee.getDefaultBucketName()))
+    default void deleteBucketShouldThrowWhenDeletingDefaultBucket() {
+        assertThatThrownBy(() ->  testee().deleteBucket(testee().getDefaultBucketName()))
             .isInstanceOf(IllegalArgumentException.class)
             .hasMessage("Deleting the default bucket is forbidden");
     }
 
     @Test
-    void blobStoreShouldSupport100MBBlob() throws IOException {
+    default void blobStoreShouldSupport100MBBlob() throws IOException {
         ZeroedInputStream data = new ZeroedInputStream(100_000_000);
         HashingInputStream writeHash = new HashingInputStream(Hashing.sha256(), data);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), writeHash, LOW_COST)).block();
+        BlobId blobId = Mono.from(testee().save(testee().getDefaultBucketName(), writeHash, LOW_COST)).block();
 
-        InputStream bytes = testee.read(testee.getDefaultBucketName(), blobId);
+        InputStream bytes = testee().read(testee().getDefaultBucketName(), blobId);
         HashingInputStream readHash = new HashingInputStream(Hashing.sha256(), bytes);
         consumeStream(readHash);
 
@@ -151,4 +109,4 @@ public class CassandraBlobStoreTest implements MetricableBlobStoreContract {
             // consume the rest of the stream
         }
     }
-}
\ No newline at end of file
+}
diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java
index ae9136b..73b031a 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraBlobStoreTest.java
@@ -19,17 +19,8 @@
 
 package org.apache.james.blob.cassandra;
 
-import static org.apache.james.blob.api.BlobStore.StoragePolicy.LOW_COST;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.IOUtils;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
@@ -38,24 +29,11 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.BucketName;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.api.MetricableBlobStore;
-import org.apache.james.blob.api.MetricableBlobStoreContract;
-import org.apache.james.blob.api.ObjectStoreException;
 import org.apache.james.server.blob.deduplication.BlobStoreFactory;
-import org.apache.james.util.io.ZeroedInputStream;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.google.common.base.Strings;
-import com.google.common.hash.Hashing;
-import com.google.common.hash.HashingInputStream;
-
-import reactor.core.publisher.Mono;
-
-public class CassandraBlobStoreTest implements MetricableBlobStoreContract {
-    private static final int CHUNK_SIZE = 10240;
-    private static final int MULTIPLE_CHUNK_SIZE = 3;
-
+public class CassandraBlobStoreTest implements CassandraBlobStoreContract {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraBlobModule.MODULE);
 
@@ -89,66 +67,8 @@ public class CassandraBlobStoreTest implements MetricableBlobStoreContract {
         return new HashBlobId.Factory();
     }
 
-    @Test
-    void readBytesShouldReturnSplitSavedDataByChunk() {
-        String longString = Strings.repeat("0123456789\n", MULTIPLE_CHUNK_SIZE);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        byte[] bytes = Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block();
-
-        assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(longString);
-    }
-
-    @Test
-    void readBytesShouldNotReturnInvalidResultsWhenPartialDataPresent() {
-        int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
-        String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
-
-        assertThatThrownBy(() -> Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block())
-            .isInstanceOf(ObjectStoreException.class)
-            .hasMessageContaining("Missing blob part for blobId");
-    }
-
-    @Test
-    void readShouldNotReturnInvalidResultsWhenPartialDataPresent() {
-        int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
-        String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
-
-        assertThatThrownBy(() -> IOUtils.toString(testee.read(testee.getDefaultBucketName(), blobId), StandardCharsets.UTF_8))
-            .isInstanceOf(ObjectStoreException.class)
-            .hasMessageContaining("Missing blob part for blobId");
-    }
-
-    @Test
-    void deleteBucketShouldThrowWhenDeletingDefaultBucket() {
-        assertThatThrownBy(() ->  testee.deleteBucket(testee.getDefaultBucketName()))
-            .isInstanceOf(IllegalArgumentException.class)
-            .hasMessage("Deleting the default bucket is forbidden");
-    }
-
-    @Test
-    void blobStoreShouldSupport100MBBlob() throws IOException {
-        ZeroedInputStream data = new ZeroedInputStream(100_000_000);
-        HashingInputStream writeHash = new HashingInputStream(Hashing.sha256(), data);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), writeHash, LOW_COST)).block();
-
-        InputStream bytes = testee.read(testee.getDefaultBucketName(), blobId);
-        HashingInputStream readHash = new HashingInputStream(Hashing.sha256(), bytes);
-        consumeStream(readHash);
-
-        assertThat(readHash.hash().toString()).isEqualTo(writeHash.hash().toString());
-    }
-
-    private void consumeStream(InputStream tmpMsgIn) throws IOException {
-        byte[] discard = new byte[4096];
-        while (tmpMsgIn.read(discard) != -1) {
-            // consume the rest of the stream
-        }
+    @Override
+    public CassandraDefaultBucketDAO defaultBucketDAO() {
+        return defaultBucketDAO;
     }
 }
\ No newline at end of file
diff --git a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraPassTroughBlobStoreTest.java b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraPassTroughBlobStoreTest.java
index 9ea1731..755dc28 100644
--- a/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraPassTroughBlobStoreTest.java
+++ b/server/blob/blob-cassandra/src/test/java/org/apache/james/blob/cassandra/CassandraPassTroughBlobStoreTest.java
@@ -19,17 +19,8 @@
 
 package org.apache.james.blob.cassandra;
 
-import static org.apache.james.blob.api.BlobStore.StoragePolicy.LOW_COST;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assertions.assertThatThrownBy;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-import org.apache.commons.io.IOUtils;
 import org.apache.james.backends.cassandra.CassandraCluster;
 import org.apache.james.backends.cassandra.CassandraClusterExtension;
 import org.apache.james.backends.cassandra.init.configuration.CassandraConfiguration;
@@ -38,23 +29,11 @@ import org.apache.james.blob.api.BlobStore;
 import org.apache.james.blob.api.BucketName;
 import org.apache.james.blob.api.HashBlobId;
 import org.apache.james.blob.api.MetricableBlobStore;
-import org.apache.james.blob.api.MetricableBlobStoreContract;
-import org.apache.james.blob.api.ObjectStoreException;
 import org.apache.james.server.blob.deduplication.BlobStoreFactory;
-import org.apache.james.util.io.ZeroedInputStream;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.RegisterExtension;
 
-import com.google.common.base.Strings;
-import com.google.common.hash.Hashing;
-import com.google.common.hash.HashingInputStream;
-import reactor.core.publisher.Mono;
-
-public class CassandraPassTroughBlobStoreTest implements MetricableBlobStoreContract {
-    private static final int CHUNK_SIZE = 10240;
-    private static final int MULTIPLE_CHUNK_SIZE = 3;
-
+public class CassandraPassTroughBlobStoreTest implements CassandraBlobStoreContract {
     @RegisterExtension
     static CassandraClusterExtension cassandraCluster = new CassandraClusterExtension(CassandraBlobModule.MODULE);
 
@@ -88,66 +67,8 @@ public class CassandraPassTroughBlobStoreTest implements MetricableBlobStoreCont
         return new HashBlobId.Factory();
     }
 
-    @Test
-    void readBytesShouldReturnSplitSavedDataByChunk() {
-        String longString = Strings.repeat("0123456789\n", MULTIPLE_CHUNK_SIZE);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        byte[] bytes = Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block();
-
-        assertThat(new String(bytes, StandardCharsets.UTF_8)).isEqualTo(longString);
-    }
-
-    @Test
-    void readBytesShouldNotReturnInvalidResultsWhenPartialDataPresent() {
-        int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
-        String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
-
-        assertThatThrownBy(() -> Mono.from(testee.readBytes(testee.getDefaultBucketName(), blobId)).block())
-            .isInstanceOf(ObjectStoreException.class)
-            .hasMessageContaining("Missing blob part for blobId");
-    }
-
-    @Test
-    void readShouldNotReturnInvalidResultsWhenPartialDataPresent() {
-        int repeatCount = MULTIPLE_CHUNK_SIZE * CHUNK_SIZE;
-        String longString = Strings.repeat("0123456789\n", repeatCount);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), longString, LOW_COST)).block();
-
-        when(defaultBucketDAO.readPart(blobId, 1)).thenReturn(Mono.empty());
-
-        assertThatThrownBy(() -> IOUtils.toString(testee.read(testee.getDefaultBucketName(), blobId), StandardCharsets.UTF_8))
-            .isInstanceOf(ObjectStoreException.class)
-            .hasMessageContaining("Missing blob part for blobId");
-    }
-
-    @Test
-    void deleteBucketShouldThrowWhenDeletingDefaultBucket() {
-        assertThatThrownBy(() ->  testee.deleteBucket(testee.getDefaultBucketName()))
-            .isInstanceOf(IllegalArgumentException.class)
-            .hasMessage("Deleting the default bucket is forbidden");
-    }
-
-    @Test
-    void blobStoreShouldSupport100MBBlob() throws IOException {
-        ZeroedInputStream data = new ZeroedInputStream(100_000_000);
-        HashingInputStream writeHash = new HashingInputStream(Hashing.sha256(), data);
-        BlobId blobId = Mono.from(testee.save(testee.getDefaultBucketName(), writeHash, LOW_COST)).block();
-
-        InputStream bytes = testee.read(testee.getDefaultBucketName(), blobId);
-        HashingInputStream readHash = new HashingInputStream(Hashing.sha256(), bytes);
-        consumeStream(readHash);
-
-        assertThat(readHash.hash().toString()).isEqualTo(writeHash.hash().toString());
-    }
-
-    private void consumeStream(InputStream tmpMsgIn) throws IOException {
-        byte[] discard = new byte[4096];
-        while (tmpMsgIn.read(discard) != -1) {
-            // consume the rest of the stream
-        }
+    @Override
+    public CassandraDefaultBucketDAO defaultBucketDAO() {
+        return defaultBucketDAO;
     }
 }
\ 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