com.couchbase.lite.syncgateway.GzippedAttachmentTest.java Source code

Java tutorial

Introduction

Here is the source code for com.couchbase.lite.syncgateway.GzippedAttachmentTest.java

Source

/**
 * Copyright (c) 2016 Couchbase, Inc. All rights reserved.
 *
 * Licensed 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 com.couchbase.lite.syncgateway;

import com.couchbase.lite.Attachment;
import com.couchbase.lite.CouchbaseLiteException;
import com.couchbase.lite.Database;
import com.couchbase.lite.DatabaseOptions;
import com.couchbase.lite.Document;
import com.couchbase.lite.LiteTestCaseWithDB;
import com.couchbase.lite.UnsavedRevision;
import com.couchbase.lite.replicator.Replication;
import com.couchbase.lite.support.Base64;
import com.couchbase.lite.util.Log;

import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Created by hideki on 5/7/15.
 */
public class GzippedAttachmentTest extends LiteTestCaseWithDB {

    public static final String TAG = "GzippedAttachmentTest";

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        if (!syncgatewayTestsEnabled()) {
            return;
        }
    }

    /**
     * https://github.com/couchbase/couchbase-lite-android/issues/197
     * Gzipped attachment support with Replicator does not seem to be working
     * <p/>
     * https://github.com/couchbase/couchbase-lite-android/blob/master/src/androidTest/java/com/couchbase/lite/replicator/ReplicationTest.java#L2071
     */
    public void testGzippedAttachment() throws Exception {
        if (!syncgatewayTestsEnabled()) {
            return;
        }

        Database pushDB = manager.getDatabase("pushdb");
        Database pullDB = manager.getDatabase("pulldb");

        String attachmentName = "attachment.png";

        // 1. store attachment with doc
        // 1.a load attachment data from asset
        InputStream attachmentStream = getAsset(attachmentName);
        java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
        IOUtils.copy(attachmentStream, baos);
        baos.close();
        attachmentStream.close();
        byte[] bytes = baos.toByteArray();

        // 1.b apply GZIP + Base64
        String attachmentBase64 = Base64.encodeBytes(bytes, Base64.GZIP);

        // 1.c attachment Map object
        Map<String, Object> attachmentMap = new HashMap<String, Object>();
        attachmentMap.put("content_type", "image/png");
        attachmentMap.put("data", attachmentBase64);
        attachmentMap.put("encoding", "gzip");
        attachmentMap.put("length", bytes.length);

        // 1.d attachments Map object
        Map<String, Object> attachmentsMap = new HashMap<String, Object>();
        attachmentsMap.put(attachmentName, attachmentMap);

        // 1.e document property Map object
        Map<String, Object> propsMap = new HashMap<String, Object>();
        propsMap.put("_attachments", attachmentsMap);

        // 1.f store document into database
        Document putDoc = pushDB.createDocument();
        putDoc.putProperties(propsMap);
        String docId = putDoc.getId();

        URL remote = getReplicationURL();

        // push
        final CountDownLatch latch1 = new CountDownLatch(1);
        Replication pusher = pushDB.createPushReplication(remote);
        pusher.addChangeListener(new Replication.ChangeListener() {
            @Override
            public void changed(Replication.ChangeEvent event) {
                Log.e(TAG, "push 1:" + event.toString());
                if (event.getCompletedChangeCount() > 0) {
                    latch1.countDown();
                }
            }
        });
        runReplication(pusher);
        assertTrue(latch1.await(30, TimeUnit.SECONDS));

        // pull
        Replication puller = pullDB.createPullReplication(remote);
        final CountDownLatch latch2 = new CountDownLatch(1);
        puller.addChangeListener(new Replication.ChangeListener() {
            @Override
            public void changed(Replication.ChangeEvent event) {
                Log.e(TAG, "pull 1:" + event.toString());
                if (event.getCompletedChangeCount() > 0) {
                    latch2.countDown();
                }
            }
        });
        runReplication(puller);
        assertTrue(latch2.await(30, TimeUnit.SECONDS));

        Log.e(TAG, "Fetching doc1 via id: " + docId);
        Document pullDoc = pullDB.getDocument(docId);
        assertNotNull(pullDoc);
        assertTrue(pullDoc.getCurrentRevisionId().startsWith("1-"));
        Attachment attachment = pullDoc.getCurrentRevision().getAttachment(attachmentName);

        assertEquals(bytes.length, attachment.getLength());
        assertEquals("image/png", attachment.getContentType());
        assertEquals("gzip", attachment.getMetadata().get("encoding"));

        InputStream is = attachment.getContent();
        byte[] receivedBytes = getBytesFromInputStream(is);
        assertEquals(bytes.length, receivedBytes.length);
        is.close();

        assertTrue(Arrays.equals(bytes, receivedBytes));

        pushDB.close();
        pullDB.close();

        pushDB.delete();
        pullDB.delete();
    }

    private static byte[] getBytesFromInputStream(InputStream is) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 8];
        int len = 0;
        try {
            while ((len = is.read(buffer)) > 0) {
                os.write(buffer, 0, len);
            }
            os.flush();
        } catch (IOException e) {
            Log.e(Log.TAG, "is.read(buffer) or os.flush() error", e);
            return null;
        }
        return os.toByteArray();
    }

    public void testImageAttachmentReplication() throws Exception {
        if (!syncgatewayTestsEnabled()) {
            return;
        }

        URL remote = getReplicationURL();

        Database pushDB = getDatabase("pushdb");
        pushDB.delete();
        pushDB = getDatabase("pushdb");

        Database pullDB = getDatabase("pulldb");
        pullDB.delete();
        pullDB = getDatabase("pulldb");

        // Create a document with an image attached:
        Map<String, Object> props = new HashMap<String, Object>();
        props.put("foo", "bar");

        Document doc = pushDB.createDocument();
        doc.putProperties(props);
        UnsavedRevision newRev = doc.createRevision();
        newRev.setAttachment("attachment", "image/png", getAsset("attachment.png"));
        newRev.save();
        String docId = doc.getId();

        // Push:
        final CountDownLatch latch1 = new CountDownLatch(1);
        Replication pusher = pushDB.createPushReplication(remote);
        pusher.addChangeListener(new Replication.ChangeListener() {
            @Override
            public void changed(Replication.ChangeEvent event) {
                Log.e(TAG, "push 1:" + event.toString());
                if (event.getCompletedChangeCount() > 0) {
                    latch1.countDown();
                }
            }
        });
        runReplication(pusher);
        assertTrue(latch1.await(5, TimeUnit.SECONDS));

        // Pull:
        Replication puller = pullDB.createPullReplication(remote);
        final CountDownLatch latch2 = new CountDownLatch(1);
        puller.addChangeListener(new Replication.ChangeListener() {
            @Override
            public void changed(Replication.ChangeEvent event) {
                Log.e(TAG, "pull 1:" + event.toString());
                if (event.getCompletedChangeCount() > 0) {
                    latch2.countDown();
                }
            }
        });
        runReplication(puller);
        assertTrue(latch2.await(5, TimeUnit.SECONDS));

        // Check document:
        Document pullDoc = pullDB.getDocument(docId);
        assertNotNull(pullDoc);
        assertTrue(pullDoc.getCurrentRevisionId().startsWith("2-"));

        // Check attachment:
        Attachment attachment = pullDoc.getCurrentRevision().getAttachment("attachment");
        byte[] originalBytes = getBytesFromInputStream(getAsset("attachment.png"));
        assertEquals(originalBytes.length, attachment.getLength());
        assertEquals("image/png", attachment.getContentType());
        assertTrue(Arrays.equals(originalBytes, getBytesFromInputStream(attachment.getContent())));

        pushDB.close();
        pullDB.close();

        pushDB.delete();
        pullDB.delete();
    }

    private Database getDatabase(String name) throws CouchbaseLiteException {
        DatabaseOptions options = new DatabaseOptions();
        options.setCreate(true);
        if (isEncryptionTestEnabled())
            options.setEncryptionKey("seekrit");
        return manager.openDatabase(name, options);
    }
}