Added: 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java?rev=1837047&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
 Mon Jul 30 11:05:10 2018
@@ -0,0 +1,524 @@
+/*
+ * 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.jackrabbit.oak.plugins.blob.datastore.directaccess;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Map;
+
+import javax.net.ssl.HttpsURLConnection;
+
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.oak.api.blob.BlobDownloadOptions;
+import org.apache.jackrabbit.util.Base64;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static com.google.common.io.ByteStreams.toByteArray;
+import static 
org.apache.jackrabbit.oak.plugins.blob.datastore.DataStoreUtils.randomStream;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public abstract class AbstractDataRecordAccessProviderTest {
+    protected static final Logger LOG = 
LoggerFactory.getLogger(AbstractDataRecordAccessProviderTest.class);
+
+    protected abstract ConfigurableDataRecordAccessProvider getDataStore();
+    protected abstract long getProviderMinPartSize();
+    protected abstract long getProviderMaxPartSize();
+    protected abstract long getProviderMaxSinglePutSize();
+    protected abstract long getProviderMaxBinaryUploadSize();
+    protected abstract boolean isSinglePutURI(URI url);
+    protected abstract HttpsURLConnection getHttpsConnection(long length, URI 
url) throws IOException;
+    protected abstract DataRecord doGetRecord(DataStore ds, DataIdentifier 
identifier) throws DataStoreException;
+    protected abstract DataRecord doSynchronousAddRecord(DataStore ds, 
InputStream in) throws DataStoreException;
+    protected abstract void doDeleteRecord(DataStore ds, DataIdentifier 
identifier) throws DataStoreException;
+
+    protected static int expirySeconds = 60*15;
+
+    protected static long ONE_KB = 1024;
+    protected static long ONE_MB = ONE_KB * ONE_KB;
+
+    protected static long TEN_MB = ONE_MB * 10;
+    protected static long TWENTY_MB = ONE_MB * 20;
+    protected static long ONE_HUNDRED_MB = ONE_MB * 100;
+    protected static long FIVE_HUNDRED_MB = ONE_HUNDRED_MB * 5;
+    protected static long ONE_GB = ONE_HUNDRED_MB * 10;
+    protected static long FIVE_GB = ONE_GB * 5;
+
+    //
+    // Direct download tests
+    //
+    @Test
+    public void testGetDownloadURIProvidesValidURI() {
+        DataIdentifier id = new DataIdentifier("testIdentifier");
+        URI uri = getDataStore().getDownloadURI(id, 
DataRecordDownloadOptions.DEFAULT);
+        assertNotNull(uri);
+    }
+
+    @Test
+    public void testGetDownloadURIRequiresValidIdentifier() {
+        try {
+            getDataStore().getDownloadURI(null, 
DataRecordDownloadOptions.DEFAULT);
+            fail();
+        }
+        catch (NullPointerException | IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testGetDownloadURIRequiresValidDownloadOptions() {
+        try {
+            getDataStore().getDownloadURI(new DataIdentifier("testIdentifier"),
+                    null);
+            fail();
+        }
+        catch (NullPointerException | IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testGetDownloadURIExpirationOfZeroFails() {
+        ConfigurableDataRecordAccessProvider dataStore = getDataStore();
+        try {
+            dataStore.setDirectDownloadURIExpirySeconds(0);
+            assertNull(dataStore.getDownloadURI(new 
DataIdentifier("testIdentifier"), DataRecordDownloadOptions.DEFAULT));
+        }
+        finally {
+            dataStore.setDirectDownloadURIExpirySeconds(expirySeconds);
+        }
+    }
+
+    @Test
+    public void testGetDownloadURIIT() throws DataStoreException, IOException {
+        DataRecord record = null;
+        DataRecordAccessProvider dataStore = getDataStore();
+        try {
+            InputStream testStream = randomStream(0, 256);
+            record = doSynchronousAddRecord((DataStore) dataStore, testStream);
+            URI uri = dataStore.getDownloadURI(record.getIdentifier(), 
DataRecordDownloadOptions.DEFAULT);
+            HttpsURLConnection conn = (HttpsURLConnection) 
uri.toURL().openConnection();
+            conn.setRequestMethod("GET");
+            assertEquals(200, conn.getResponseCode());
+
+            testStream.reset();
+            assertTrue(Arrays.equals(toByteArray(testStream), 
toByteArray(conn.getInputStream())));
+        }
+        finally {
+            if (null != record) {
+                doDeleteRecord((DataStore) dataStore, record.getIdentifier());
+            }
+        }
+    }
+
+    @Test
+    public void testGetDownloadURIWithCustomHeadersIT() throws 
DataStoreException, IOException {
+        DataRecord record = null;
+        DataRecordAccessProvider dataStore = getDataStore();
+        try {
+            InputStream testStream = randomStream(0, 256);
+            record = doSynchronousAddRecord((DataStore) dataStore, testStream);
+            String mimeType = "image/png";
+            String fileName = "album cover.png";
+            String dispositionType = "inline";
+            DataRecordDownloadOptions downloadOptions =
+                    DataRecordDownloadOptions.fromBlobDownloadOptions(
+                            new BlobDownloadOptions(
+                                    mimeType,
+                                    null,
+                                    fileName,
+                                    dispositionType
+                            )
+                    );
+            URI uri = dataStore.getDownloadURI(record.getIdentifier(),
+                    downloadOptions);
+
+            HttpsURLConnection conn = (HttpsURLConnection) 
uri.toURL().openConnection();
+            conn.setRequestMethod("GET");
+            assertEquals(200, conn.getResponseCode());
+
+            assertEquals(mimeType, conn.getHeaderField("Content-Type"));
+            assertEquals(
+                    String.format("%s; filename=\"%s\"; filename*=UTF-8''%s",
+                            dispositionType, fileName,
+                            new 
String(fileName.getBytes(StandardCharsets.UTF_8))
+                    ),
+                    conn.getHeaderField("Content-Disposition")
+            );
+
+            testStream.reset();
+            assertTrue(Arrays.equals(toByteArray(testStream), 
toByteArray(conn.getInputStream())));
+        }
+        finally {
+            if (null != record) {
+                doDeleteRecord((DataStore) dataStore, record.getIdentifier());
+            }
+        }
+    }
+
+    @Test
+    public void testGetExpiredReadURIFailsIT() throws DataStoreException, 
IOException {
+        DataRecord record = null;
+        ConfigurableDataRecordAccessProvider dataStore = getDataStore();
+        try {
+            dataStore.setDirectDownloadURIExpirySeconds(2);
+            record = doSynchronousAddRecord((DataStore) dataStore, 
randomStream(0, 256));
+            URI uri = dataStore.getDownloadURI(record.getIdentifier(), 
DataRecordDownloadOptions.DEFAULT);
+            try {
+                Thread.sleep(5 * 1000);
+            } catch (InterruptedException e) {
+            }
+            HttpsURLConnection conn = (HttpsURLConnection) 
uri.toURL().openConnection();
+            conn.setRequestMethod("GET");
+            assertEquals(403, conn.getResponseCode());
+        }
+        finally {
+            if (null != record) {
+                doDeleteRecord((DataStore) dataStore, record.getIdentifier());
+            }
+            dataStore.setDirectDownloadURIExpirySeconds(expirySeconds);
+        }
+    }
+
+    //
+    // Direct upload tests
+    //
+    @Test
+    public void testInitiateDirectUploadReturnsValidUploadContext() throws 
DataRecordUploadException {
+        DataRecordUpload uploadContext =
+                getDataStore().initiateDataRecordUpload(ONE_MB, 10);
+        assertNotNull(uploadContext);
+        assertFalse(uploadContext.getUploadURIs().isEmpty());
+        assertTrue(uploadContext.getMinPartSize() > 0);
+        assertTrue(uploadContext.getMinPartSize() >= getProviderMinPartSize());
+        assertTrue(uploadContext.getMaxPartSize() >= 
uploadContext.getMinPartSize());
+        assertTrue(uploadContext.getMaxPartSize() <= getProviderMaxPartSize());
+        assertTrue((uploadContext.getMaxPartSize() * 
uploadContext.getUploadURIs().size()) >= ONE_MB);
+        assertFalse(Strings.isNullOrEmpty(uploadContext.getUploadToken()));
+    }
+
+    @Test
+    public void testInitiateDirectUploadRequiresNonzeroFileSize() throws 
DataRecordUploadException {
+        try {
+            getDataStore().initiateDataRecordUpload(0, 10);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testInititateDirectUploadRequiresNonzeroNumURIs() throws 
DataRecordUploadException {
+        try {
+            getDataStore().initiateDataRecordUpload(ONE_MB, 0);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testInitiateDirectUploadRequiresNonNegativeNumURIs()
+            throws DataRecordUploadException {
+        try {
+            getDataStore().initiateDataRecordUpload(ONE_MB, -2);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+
+        // -1 is allowed which means any number of URIs
+        try {
+            
assertNotNull(getDataStore().initiateDataRecordUpload(ONE_HUNDRED_MB, -1));
+        }
+        catch (IllegalArgumentException e) {
+            fail();
+        }
+    }
+
+    @Test
+    public void testInititateDirectUploadSingleURIRequested() throws 
DataRecordUploadException {
+        DataRecordUpload uploadContext =
+                getDataStore().initiateDataRecordUpload(TWENTY_MB, 1);
+        assertEquals(1, uploadContext.getUploadURIs().size());
+        
assertTrue(isSinglePutURI(uploadContext.getUploadURIs().iterator().next()));
+    }
+
+    @Test
+    public void testInititateDirectUploadSizeLowerThanMinPartSize() throws 
DataRecordUploadException {
+        DataRecordUpload uploadContext =
+                
getDataStore().initiateDataRecordUpload(getProviderMinPartSize()-1L, 10);
+        assertEquals(1, uploadContext.getUploadURIs().size());
+        
assertTrue(isSinglePutURI(uploadContext.getUploadURIs().iterator().next()));
+    }
+
+    @Test
+    public void testInititateDirectUploadMultiPartDisabled() throws 
DataRecordUploadException {
+        ConfigurableDataRecordAccessProvider ds = getDataStore();
+        try {
+            ds.setDirectUploadURIExpirySeconds(0);
+            DataRecordUpload uploadContext = 
ds.initiateDataRecordUpload(TWENTY_MB, 10);
+            assertEquals(0, uploadContext.getUploadURIs().size());
+
+            uploadContext = ds.initiateDataRecordUpload(20, 1);
+            assertEquals(0, uploadContext.getUploadURIs().size());
+        }
+        finally {
+            ds.setDirectUploadURIExpirySeconds(expirySeconds);
+        }
+    }
+
+    @Test
+    public void testInititateDirectUploadURIListSizes() throws 
DataRecordUploadException {
+        DataRecordAccessProvider ds = getDataStore();
+        for (InitUploadResult res : Lists.newArrayList(
+                // 20MB upload and 10 URIs requested => should result in 2 
URIs (10MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return TWENTY_MB; }
+                    @Override public int getMaxNumURIs() { return 10; }
+                    @Override public int getExpectedNumURIs() { return 2; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 100MB upload and 10 URIs requested => should result in 10 
URIs (10MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
ONE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 10; }
+                    @Override public int getExpectedNumURIs() { return 10; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 100MB upload and 5 URIs requested => should result in 5 
URIs (20MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
ONE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 5; }
+                    @Override public int getExpectedNumURIs() { return 5; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 500MB upload and 50 URIs requested => should result in 50 
URIs (10MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
FIVE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 50; }
+                    @Override public int getExpectedNumURIs() { return 50; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 500MB upload and 10 URIs requested => should result in 10 
URIs (50MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
FIVE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 10; }
+                    @Override public int getExpectedNumURIs() { return 10; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 500MB upload and 60 URIs requested => should result in 50 
uls (10MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
FIVE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 60; }
+                    @Override public int getExpectedNumURIs() { return 50; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 500MB upload and 5 URIs requested => should result in 5 
URIs (100MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return 
FIVE_HUNDRED_MB; }
+                    @Override public int getMaxNumURIs() { return 5; }
+                    @Override public int getExpectedNumURIs() { return 5; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 1GB upload and 10 URIs requested => should result in 10 
URIs (100MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return ONE_GB; }
+                    @Override public int getMaxNumURIs() { return 10; }
+                    @Override public int getExpectedNumURIs() { return 10; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                },
+                // 5GB upload and 50 URIs requested => should result in 50 
URIs (100MB each)
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return FIVE_GB; }
+                    @Override public int getMaxNumURIs() { return 50; }
+                    @Override public int getExpectedNumURIs() { return 50; }
+                    @Override public long getExpectedMinPartSize() { return 
getProviderMinPartSize(); }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                }
+        )) {
+            DataRecordUpload uploadContext = 
ds.initiateDataRecordUpload(res.getUploadSize(), res.getMaxNumURIs());
+            assertEquals(String.format("Failed for upload size: %d, num URIs 
%d", res.getUploadSize(), res.getMaxNumURIs()),
+                    res.getExpectedNumURIs(), 
uploadContext.getUploadURIs().size());
+            assertEquals(String.format("Failed for upload size: %d, num URIs 
%d", res.getUploadSize(), res.getMaxNumURIs()),
+                    res.getExpectedMinPartSize(), 
uploadContext.getMinPartSize());
+            assertEquals(String.format("Failed for upload size: %d, num URIs 
%d", res.getUploadSize(), res.getMaxNumURIs()),
+                    res.getExpectedMaxPartSize(), 
uploadContext.getMaxPartSize());
+        }
+    }
+
+    @Test
+    public void testInitiateDirectUploadSizeTooBigForSinglePut() throws 
DataRecordUploadException {
+        try {
+            
getDataStore().initiateDataRecordUpload(getProviderMaxSinglePutSize() + 1, 1);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testInitiateDirectUploadSizeTooBigForUpload() throws 
DataRecordUploadException {
+        try {
+            
getDataStore().initiateDataRecordUpload(getProviderMaxBinaryUploadSize() + 1, 
-1);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testInititateDirectUploadRequestedPartSizesTooBig() throws 
DataRecordUploadException {
+        try {
+            getDataStore().initiateDataRecordUpload(FIVE_GB, 5);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testCompleteDirectUploadRequiresNonNullToken() throws 
DataRecordUploadException, DataStoreException {
+        try {
+            getDataStore().completeDataRecordUpload(null);
+            fail();
+        }
+        catch (NullPointerException | IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testCompleteDirectUploadRequiresValidToken() throws 
DataRecordUploadException, DataStoreException {
+        for (String token : Lists.newArrayList("", "abc", "abc#123")) {
+            try {
+                getDataStore().completeDataRecordUpload(token);
+                fail();
+            }
+            catch (IllegalArgumentException e) { }
+        }
+    }
+
+    @Test
+    public void testCompleteDirectUploadSignatureMustMatch() throws 
DataRecordUploadException, DataStoreException {
+        DataRecordUpload uploadContext = 
getDataStore().initiateDataRecordUpload(ONE_MB, 1);
+
+        // Pull the blob id out and modify it
+        String uploadToken = uploadContext.getUploadToken();
+        String[] parts = uploadToken.split("#");
+        String tokenPart = parts[0];
+        String sigPart = parts[1];
+        String[] subParts = tokenPart.split("#");
+        String blobId = subParts[0];
+        char c = (char)((int)(blobId.charAt(blobId.length()-1))+1);
+        blobId = blobId.substring(0, blobId.length()-1) + c;
+        for (int i = 1; i<subParts.length; i++) {
+            blobId += "#" + subParts[i];
+        }
+        String newToken = Base64.encode(blobId) + "#" + sigPart;
+
+        try {
+            getDataStore().completeDataRecordUpload(newToken);
+            fail();
+        }
+        catch (IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testSinglePutDirectUploadIT() throws 
DataRecordUploadException, DataStoreException, IOException {
+        DataRecordAccessProvider ds = getDataStore();
+        for (InitUploadResult res : Lists.newArrayList(
+                new InitUploadResult() {
+                    @Override public long getUploadSize() { return ONE_MB; }
+                    @Override public int getMaxNumURIs() { return 10; }
+                    @Override public int getExpectedNumURIs() { return 1; }
+                    @Override public long getExpectedMinPartSize() { return 
TEN_MB; }
+                    @Override public long getExpectedMaxPartSize() { return 
getProviderMaxPartSize(); }
+                }
+        )) {
+            DataRecord uploadedRecord = null;
+            try {
+                DataRecordUpload uploadContext = 
ds.initiateDataRecordUpload(res.getUploadSize(), res.getMaxNumURIs());
+
+                assertEquals(res.getExpectedNumURIs(), 
uploadContext.getUploadURIs().size());
+
+                InputStream uploadStream = randomStream(0, (int) 
res.getUploadSize());
+                URI uploadURI = 
uploadContext.getUploadURIs().iterator().next();
+                doHttpsUpload(uploadStream, res.getUploadSize(), uploadURI);
+
+                uploadedRecord = 
ds.completeDataRecordUpload(uploadContext.getUploadToken());
+                assertNotNull(uploadedRecord);
+
+                DataRecord retrievedRecord = doGetRecord((DataStore) ds, 
uploadedRecord.getIdentifier());
+                assertNotNull(retrievedRecord);
+                uploadStream.reset();
+                assertTrue(Arrays.equals(toByteArray(uploadStream), 
toByteArray(retrievedRecord.getStream())));
+            }
+            finally {
+                if (null != uploadedRecord) {
+                    doDeleteRecord((DataStore) ds, 
uploadedRecord.getIdentifier());
+                }
+            }
+        }
+    }
+
+    protected Map<String, String> parseQueryString(URI uri) {
+        Map<String, String> parsed = Maps.newHashMap();
+        String query = uri.getQuery();
+        try {
+            for (String pair : query.split("&")) {
+                String[] kv = pair.split("=", 2);
+                parsed.put(URLDecoder.decode(kv[0], "utf-8"), 
URLDecoder.decode(kv[1], "utf-8"));
+            }
+        }
+        catch (UnsupportedEncodingException e) {
+            LOG.error("UnsupportedEncodingException caught", e);
+        }
+        return parsed;
+    }
+
+    protected void doHttpsUpload(InputStream in, long contentLength, URI uri) 
throws IOException {
+        HttpsURLConnection conn = getHttpsConnection(contentLength, uri);
+        IOUtils.copy(in, conn.getOutputStream());
+        int responseCode = conn.getResponseCode();
+        assertTrue(conn.getResponseMessage(), responseCode < 400);
+    }
+
+    interface InitUploadResult {
+        long getUploadSize();
+        int getMaxNumURIs();
+        int getExpectedNumURIs();
+        long getExpectedMinPartSize();
+        long getExpectedMaxPartSize();
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/AbstractDataRecordAccessProviderTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java?rev=1837047&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java
 Mon Jul 30 11:05:10 2018
@@ -0,0 +1,256 @@
+/*
+ * 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.jackrabbit.oak.plugins.blob.datastore.directaccess;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import java.nio.charset.StandardCharsets;
+
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import org.apache.jackrabbit.oak.api.blob.BlobDownloadOptions;
+import org.junit.Test;
+
+public class DataRecordDownloadOptionsTest {
+    private static final String MEDIA_TYPE_IMAGE_PNG = "image/png";
+    private static final String MEDIA_TYPE_TEXT_PLAIN = "text/plain";
+    private static final String CHARACTER_ENCODING_UTF_8 = "utf-8";
+    private static final String CHARACTER_ENCODING_ISO_8859_1 = "ISO-8859-1";
+    private static final String FILE_NAME_IMAGE = "amazing summer sunset.png";
+    private static final String FILE_NAME_TEXT = 
"journal_entry_01-01-2000.txt";
+    private static final String DISPOSITION_TYPE_INLINE = "inline";
+    private static final String DISPOSITION_TYPE_ATTACHMENT = "attachment";
+
+    private void verifyOptions(DataRecordDownloadOptions options,
+                               String mediaType,
+                               String characterEncoding,
+                               String fileName,
+                               String dispositionType) {
+        assertNotNull(options);
+        if (null != mediaType) {
+            assertEquals(mediaType, options.getMediaType());
+        }
+        else {
+            assertNull(options.getMediaType());
+        }
+        if (null != characterEncoding) {
+            assertEquals(characterEncoding, options.getCharacterEncoding());
+        }
+        else {
+            assertNull(options.getCharacterEncoding());
+        }
+        if (null != dispositionType) {
+            assertEquals(dispositionType, options.getDispositionType());
+        }
+        else {
+            assertEquals(DISPOSITION_TYPE_ATTACHMENT, 
options.getDispositionType());
+        }
+        if (null != fileName) {
+            assertEquals(fileName, options.getFileName());
+        }
+        else {
+            assertNull(options.getFileName());
+        }
+    }
+
+    private void verifyContentTypeHeader(DataRecordDownloadOptions options,
+                                         String contentTypeHeader) {
+        if (Strings.isNullOrEmpty(contentTypeHeader)) {
+            assertNull(options.getContentTypeHeader());
+        }
+        else {
+            assertEquals(contentTypeHeader, options.getContentTypeHeader());
+        }
+    }
+
+    private void verifyContentDispositionHeader(DataRecordDownloadOptions 
options,
+                                                String 
contentDispositionHeader) {
+        if (Strings.isNullOrEmpty(contentDispositionHeader)) {
+            assertNull(options.getContentDispositionHeader());
+        }
+        else {
+            assertEquals(contentDispositionHeader, 
options.getContentDispositionHeader());
+        }
+    }
+
+    private DataRecordDownloadOptions getOptions(String mediaType,
+                                                 String characterEncoding,
+                                                 String fileName,
+                                                 String dispositionType) {
+        if (null == dispositionType) {
+            dispositionType = 
DataRecordDownloadOptions.DISPOSITION_TYPE_INLINE;
+        }
+        return DataRecordDownloadOptions.fromBlobDownloadOptions(
+                new BlobDownloadOptions(mediaType,
+                        characterEncoding,
+                        fileName,
+                        dispositionType)
+        );
+    }
+
+    private String getContentTypeHeader(String mediaType, String 
characterEncoding) {
+        return Strings.isNullOrEmpty(mediaType) ?
+                null :
+                (Strings.isNullOrEmpty(characterEncoding) ?
+                        mediaType :
+                        Joiner.on("; charset=").join(mediaType, 
characterEncoding)
+                );
+    }
+
+    private String getContentDispositionHeader(String fileName, String 
dispositionType) {
+        if (Strings.isNullOrEmpty(fileName)) {
+            if (dispositionType.equals(DISPOSITION_TYPE_ATTACHMENT)) {
+                return DISPOSITION_TYPE_ATTACHMENT;
+            }
+            return null;
+        }
+
+        if (Strings.isNullOrEmpty(dispositionType)) {
+            dispositionType = DISPOSITION_TYPE_INLINE;
+        }
+        String fileNameStar = new 
String(fileName.getBytes(StandardCharsets.UTF_8));
+        return String.format("%s; filename=\"%s\"; filename*=UTF-8''%s",
+                dispositionType, fileName, fileNameStar);
+    }
+
+    @Test
+    public void testConstruct() {
+        BlobDownloadOptions blobDownloadOptions =
+                new BlobDownloadOptions(
+                        MEDIA_TYPE_TEXT_PLAIN,
+                        CHARACTER_ENCODING_UTF_8,
+                        FILE_NAME_TEXT,
+                        DISPOSITION_TYPE_ATTACHMENT
+                );
+        DataRecordDownloadOptions options =
+                
DataRecordDownloadOptions.fromBlobDownloadOptions(blobDownloadOptions);
+
+        verifyOptions(options,
+                MEDIA_TYPE_TEXT_PLAIN,
+                CHARACTER_ENCODING_UTF_8,
+                FILE_NAME_TEXT,
+                DISPOSITION_TYPE_ATTACHMENT);
+    }
+
+    @Test
+    public void testDefault() {
+        verifyOptions(DataRecordDownloadOptions.DEFAULT,
+                null,
+                null,
+                null,
+                DISPOSITION_TYPE_INLINE);
+        verifyOptions(DataRecordDownloadOptions
+                .fromBlobDownloadOptions(BlobDownloadOptions.DEFAULT),
+                null,
+                null,
+                null,
+                DISPOSITION_TYPE_INLINE);
+    }
+
+    @Test
+    public void testConstructFromNullThrowsException() {
+        try {
+            DataRecordDownloadOptions.fromBlobDownloadOptions(null);
+            fail();
+        }
+        catch (NullPointerException | IllegalArgumentException e) { }
+    }
+
+    @Test
+    public void testGetContentTypeHeader() {
+        for (String mediaType : Lists.newArrayList(MEDIA_TYPE_TEXT_PLAIN, 
MEDIA_TYPE_IMAGE_PNG)) {
+            for (String characterEncoding : 
Lists.newArrayList(CHARACTER_ENCODING_UTF_8, CHARACTER_ENCODING_ISO_8859_1)) {
+                verifyContentTypeHeader(
+                        getOptions(mediaType, characterEncoding, null, null),
+                        getContentTypeHeader(mediaType, characterEncoding)
+                );
+            }
+        }
+    }
+
+    @Test
+    public void testGetContentTypeHeaderWithNoCharacterEncoding() {
+        verifyContentTypeHeader(
+                getOptions(MEDIA_TYPE_IMAGE_PNG, null, null, null),
+                MEDIA_TYPE_IMAGE_PNG
+        );
+    }
+
+    @Test
+    public void testGetContentTypeHeaderWithNoMediaType() {
+        verifyContentTypeHeader(
+                getOptions(null, CHARACTER_ENCODING_ISO_8859_1, null, null),
+                null
+        );
+    }
+
+    @Test
+    public void testGetContentTypeHeaderWithNoMediaTypeOrCharacterEncoding() {
+        verifyContentTypeHeader(
+                getOptions(null, null, null, null),
+                null
+        );
+    }
+
+    @Test
+    public void testGetContentDisposition() {
+        for (String fileName : Lists.newArrayList(FILE_NAME_IMAGE, 
FILE_NAME_TEXT)) {
+            for (String dispositionType : 
Lists.newArrayList(DISPOSITION_TYPE_INLINE, DISPOSITION_TYPE_ATTACHMENT)) {
+                verifyContentDispositionHeader(
+                        getOptions(null, null, fileName, dispositionType),
+                        getContentDispositionHeader(fileName, dispositionType)
+                );
+            }
+        }
+    }
+
+    @Test
+    public void testGetContentDispositionWithNoDispositionType() {
+        // Ensures that the default disposition type is "inline"
+        verifyContentDispositionHeader(
+                getOptions(null, null, FILE_NAME_IMAGE, null),
+                getContentDispositionHeader(FILE_NAME_IMAGE, 
DISPOSITION_TYPE_INLINE)
+        );
+    }
+
+    @Test
+    public void testGetContentDispositionWithNoFileName() {
+        verifyContentDispositionHeader(
+                getOptions(null, null, null, DISPOSITION_TYPE_INLINE),
+                null
+        );
+        verifyContentDispositionHeader(
+                getOptions(null, null, null, DISPOSITION_TYPE_ATTACHMENT),
+                DISPOSITION_TYPE_ATTACHMENT
+        );
+    }
+
+    @Test
+    public void testGetContentDispositionWithNoDispositionTypeOrFileName() {
+        verifyContentDispositionHeader(
+                getOptions(null, null, null, null),
+                null
+        );
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-blob-plugins/src/test/java/org/apache/jackrabbit/oak/plugins/blob/datastore/directaccess/DataRecordDownloadOptionsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to