Android Open Source - couchbase-lite-android Change Tracker Test






From Project

Back to project page couchbase-lite-android.

License

The source code is released under:

Apache License

If you think the Android project couchbase-lite-android listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

package com.couchbase.lite.replicator;
/*from  w w w.j  a  va  2 s.c om*/
import com.couchbase.lite.LiteTestCase;
import com.couchbase.lite.util.Log;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.IOException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

public class ChangeTrackerTest extends LiteTestCase {

    public static final String TAG = "ChangeTracker";

    /**
     * Test case for CBL Java Core #317 (CBL Java #39)
     * https://github.com/couchbase/couchbase-lite-java-core/issues/317
     */
    public void testChangeTrackerNullPointerException() throws Throwable {
        // Null pointer issue is not 100% reproducible. so try 10 times...
        for(int i = 0; i < 10; i++)
            changeTrackerTestWithMode(ChangeTracker.ChangeTrackerMode.OneShot, true, true);
    }

    public void testChangeTrackerOneShot() throws Throwable {
        changeTrackerTestWithMode(ChangeTracker.ChangeTrackerMode.OneShot, true, false);
    }

    public void testChangeTrackerLongPoll() throws Throwable {
        changeTrackerTestWithMode(ChangeTracker.ChangeTrackerMode.LongPoll, true, false);
    }

    public void changeTrackerTestWithMode(ChangeTracker.ChangeTrackerMode mode, final boolean useMockReplicator, final boolean checkLastException) throws Throwable {

        final CountDownLatch changeTrackerFinishedSignal = new CountDownLatch(1);
        final CountDownLatch changeReceivedSignal = new CountDownLatch(1);

        URL testURL = getReplicationURL();

        ChangeTrackerClient client = new ChangeTrackerClient() {

            @Override
            public void changeTrackerStopped(ChangeTracker tracker) {
                changeTrackerFinishedSignal.countDown();
            }

            @Override
            public void changeTrackerFinished(ChangeTracker tracker) {
            }

            @Override
            public void changeTrackerCaughtUp() {

            }

            @Override
            public void changeTrackerReceivedChange(Map<String, Object> change) {
                Object seq = change.get("seq");
                if (useMockReplicator) {
                    assertEquals("1", seq.toString());
                }
                changeReceivedSignal.countDown();
            }

            @Override
            public HttpClient getHttpClient() {
                if (useMockReplicator) {
                    CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient();
                    mockHttpClient.setResponder("_changes", new CustomizableMockHttpClient.Responder() {
                        @Override
                        public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException {
                            String json = "{\"results\":[\n" +
                                    "{\"seq\":\"1\",\"id\":\"doc1-138\",\"changes\":[{\"rev\":\"1-82d\"}]}],\n" +
                                    "\"last_seq\":\"*:50\"}";
                            return CustomizableMockHttpClient.generateHttpResponseObject(json);
                        }
                    });
                    return mockHttpClient;
                } else {
                    return new DefaultHttpClient();
                }
            }
        };

        final ChangeTracker changeTracker = new ChangeTracker(testURL, mode, false, 0, client);
        changeTracker.setUsePOST(isTestingAgainstSyncGateway());
        changeTracker.start();

        try {
            boolean success = changeReceivedSignal.await(300, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        changeTracker.stop();

        try {
            boolean success = changeTrackerFinishedSignal.await(300, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // check for NullPointer Exception or any Exception
        if(checkLastException){
            // CBL Java Core #317
            // This check does not work without fixing Java Core #317 because ChangeTracker status
            // becomes stopped before NullPointer Exception is thrown.
            if(changeTracker.getLastError() != null){
                Log.e(TAG, changeTracker.getLastError().toString());
                assertFalse(changeTracker.getLastError() instanceof NullPointerException);
            }
        }
    }

    public void testChangeTrackerWithConflictsIncluded() {

        URL testURL = getReplicationURL();
        ChangeTracker changeTracker = new ChangeTracker(testURL, ChangeTracker.ChangeTrackerMode.LongPoll, true, 0, null);

        assertEquals("_changes?feed=longpoll&limit=50&heartbeat=300000&style=all_docs&since=0", changeTracker.getChangesFeedPath());

    }

    public void testChangeTrackerWithFilterURL() throws Throwable {

        URL testURL = getReplicationURL();
        ChangeTracker changeTracker = new ChangeTracker(testURL, ChangeTracker.ChangeTrackerMode.LongPoll, false, 0, null);

        // set filter
        changeTracker.setFilterName("filter");

        // build filter map
        Map<String,Object> filterMap = new HashMap<String,Object>();
        filterMap.put("param", "value");

        // set filter map
        changeTracker.setFilterParams(filterMap);

        assertEquals("_changes?feed=longpoll&limit=50&heartbeat=300000&since=0&filter=filter&param=value", changeTracker.getChangesFeedPath());

    }

    public void testChangeTrackerWithDocsIds() {

        URL testURL = getReplicationURL();

        ChangeTracker changeTrackerDocIds = new ChangeTracker(testURL, ChangeTracker.ChangeTrackerMode.LongPoll, false, 0, null);
        List<String> docIds = new ArrayList<String>();
        docIds.add("doc1");
        docIds.add("doc2");
        changeTrackerDocIds.setDocIDs(docIds);

        String docIdsUnencoded = "[\"doc1\",\"doc2\"]";
        String docIdsEncoded = URLEncoder.encode(docIdsUnencoded);
        String expectedFeedPath = String.format("_changes?feed=longpoll&limit=50&heartbeat=300000&since=0&filter=_doc_ids&doc_ids=%s", docIdsEncoded);
        final String changesFeedPath = changeTrackerDocIds.getChangesFeedPath();
        assertEquals(expectedFeedPath, changesFeedPath);

        changeTrackerDocIds.setUsePOST(true);
        Map<String, Object> postBodyMap = changeTrackerDocIds.changesFeedPOSTBodyMap();
        assertEquals("_doc_ids", postBodyMap.get("filter"));
        assertEquals(docIds, postBodyMap.get("doc_ids"));
        String postBody = changeTrackerDocIds.changesFeedPOSTBody();
        assertTrue(postBody.contains(docIdsUnencoded));

    }

    public void testChangeTrackerBackoffExceptions() throws Throwable {
        final CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient();
        mockHttpClient.addResponderThrowExceptionAllRequests();
        testChangeTrackerBackoff(mockHttpClient);

    }

    public void testChangeTrackerBackoffInvalidJson() throws Throwable {
        final CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient();
        mockHttpClient.addResponderReturnInvalidChangesFeedJson();
        testChangeTrackerBackoff(mockHttpClient);
    }

    public void testChangeTrackerRecoverableError() throws Exception {
        int errorCode = 503;
        String statusMessage = "Transient Error";
        int numExpectedChangeCallbacks = 2;
        runChangeTrackerTransientError(ChangeTracker.ChangeTrackerMode.LongPoll, errorCode, statusMessage, numExpectedChangeCallbacks);
    }

    public void testChangeTrackerRecoverableIOException() throws Exception {
        int errorCode = -1;  // special code to tell it to throw an IOException
        String statusMessage = null;
        int numExpectedChangeCallbacks = 2;
        runChangeTrackerTransientError(ChangeTracker.ChangeTrackerMode.LongPoll, errorCode, statusMessage, numExpectedChangeCallbacks);
    }

    public void testChangeTrackerNonRecoverableError() throws Exception {
        int errorCode = 404;
        String statusMessage = "NOT FOUND";
        int numExpectedChangeCallbacks = 1;
        runChangeTrackerTransientError(ChangeTracker.ChangeTrackerMode.LongPoll, errorCode, statusMessage, numExpectedChangeCallbacks);
    }

    private void runChangeTrackerTransientError(ChangeTracker.ChangeTrackerMode mode,
                                                final int errorCode,
                                                final String statusMessage,
                                                int numExpectedChangeCallbacks) throws Exception {

        final CountDownLatch changeTrackerFinishedSignal = new CountDownLatch(1);
        final CountDownLatch changeReceivedSignal = new CountDownLatch(numExpectedChangeCallbacks);

        URL testURL = getReplicationURL();

        ChangeTrackerClient client = new ChangeTrackerClient() {

            @Override
            public void changeTrackerStopped(ChangeTracker tracker) {
                changeTrackerFinishedSignal.countDown();
            }

            @Override
            public void changeTrackerFinished(ChangeTracker tracker) {
            }

            @Override
            public void changeTrackerCaughtUp() {

            }

            @Override
            public void changeTrackerReceivedChange(Map<String, Object> change) {
                changeReceivedSignal.countDown();
            }

            @Override
            public HttpClient getHttpClient() {
                CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient();
                CustomizableMockHttpClient.Responder sentinal = defaultChangesResponder();
                Queue<CustomizableMockHttpClient.Responder> responders = new LinkedList<CustomizableMockHttpClient.Responder>();
                responders.add(defaultChangesResponder());
                responders.add(CustomizableMockHttpClient.transientErrorResponder(errorCode, statusMessage));
                ResponderChain responderChain = new ResponderChain(responders, sentinal);
                mockHttpClient.setResponder("_changes", responderChain);
                return mockHttpClient;
            }

            private CustomizableMockHttpClient.Responder defaultChangesResponder() {
                return new CustomizableMockHttpClient.Responder() {
                    @Override
                    public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException {
                        String json = "{\"results\":[\n" +
                                "{\"seq\":\"1\",\"id\":\"doc1-138\",\"changes\":[{\"rev\":\"1-82d\"}]}],\n" +
                                "\"last_seq\":\"*:50\"}";
                        return CustomizableMockHttpClient.generateHttpResponseObject(json);
                    }
                };
            }

        };

        final ChangeTracker changeTracker = new ChangeTracker(testURL, mode, false, 0, client);
        changeTracker.setUsePOST(isTestingAgainstSyncGateway());
        changeTracker.start();

        try {
            boolean success = changeReceivedSignal.await(30, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        changeTracker.stop();

        try {
            boolean success = changeTrackerFinishedSignal.await(30, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    private void testChangeTrackerBackoff(final CustomizableMockHttpClient mockHttpClient) throws Throwable {

        URL testURL = getReplicationURL();

        final CountDownLatch changeTrackerFinishedSignal = new CountDownLatch(1);

        ChangeTrackerClient client = new ChangeTrackerClient() {

            @Override
            public void changeTrackerStopped(ChangeTracker tracker) {
                Log.v(TAG, "changeTrackerStopped");
                changeTrackerFinishedSignal.countDown();
            }

            @Override
            public void changeTrackerFinished(ChangeTracker tracker) {
                Log.v(TAG, "changeTrackerFinished");
            }

            @Override
            public void changeTrackerCaughtUp() {

            }

            @Override
            public void changeTrackerReceivedChange(Map<String, Object> change) {
                Object seq = change.get("seq");
                Log.v(TAG, "changeTrackerReceivedChange: %d" + seq.toString());
            }

            @Override
            public HttpClient getHttpClient() {
                return mockHttpClient;
            }
        };

        final ChangeTracker changeTracker = new ChangeTracker(testURL, ChangeTracker.ChangeTrackerMode.LongPoll, false, 0, client);
        changeTracker.setUsePOST(isTestingAgainstSyncGateway());
        changeTracker.start();

        // sleep for a few seconds
        Thread.sleep(5 * 1000);

        // make sure we got less than 10 requests in those 10 seconds (if it was hammering, we'd get a lot more)
        assertTrue(mockHttpClient.getCapturedRequests().size() < 25);
        assertTrue(changeTracker.backoff.getNumAttempts() > 0);

        mockHttpClient.clearResponders();
        mockHttpClient.addResponderReturnEmptyChangesFeed();

        // at this point, the change tracker backoff should cause it to sleep for about 3 seconds
        // and so lets wait 3 seconds until it wakes up and starts getting valid responses
        Thread.sleep(3 * 1000);

        // now find the delta in requests received in a 2s period
        int before = mockHttpClient.getCapturedRequests().size();
        Thread.sleep(2 * 1000);
        int after = mockHttpClient.getCapturedRequests().size();

        // assert that the delta is high, because at this point the change tracker should
        // be hammering away
        assertTrue((after - before) > 25);

        // the backoff numAttempts should have been reset to 0
        assertTrue(changeTracker.backoff.getNumAttempts() == 0);

        changeTracker.stop();

        try {
            boolean success = changeTrackerFinishedSignal.await(300, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


    }

    // ChangeTrackerMode.Continuous mode does not work, do not use it.
    public void failingTestChangeTrackerContinuous() throws Throwable {

        final CountDownLatch changeTrackerFinishedSignal = new CountDownLatch(1);
        final CountDownLatch changeReceivedSignal = new CountDownLatch(1);

        URL testURL = getReplicationURL();

        ChangeTrackerClient client = new ChangeTrackerClient() {

            @Override
            public void changeTrackerStopped(ChangeTracker tracker) {
                changeTrackerFinishedSignal.countDown();
            }

            @Override
            public void changeTrackerFinished(ChangeTracker tracker) {
            }

            @Override
            public void changeTrackerCaughtUp() {

            }

            @Override
            public void changeTrackerReceivedChange(Map<String, Object> change) {
                Object seq = change.get("seq");
                changeReceivedSignal.countDown();
            }

            @Override
            public HttpClient getHttpClient() {
                return new DefaultHttpClient();
            }
        };

        final ChangeTracker changeTracker = new ChangeTracker(testURL, ChangeTracker.ChangeTrackerMode.Continuous, false, 0, client);
        changeTracker.setUsePOST(isTestingAgainstSyncGateway());
        changeTracker.start();

        try {
            boolean success = changeReceivedSignal.await(300, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        changeTracker.stop();

        try {
            boolean success = changeTrackerFinishedSignal.await(300, TimeUnit.SECONDS);
            assertTrue(success);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }



}




Java Source Code List

com.couchbase.lite.ApiTest.java
com.couchbase.lite.AttachmentsTest.java
com.couchbase.lite.AuthTest.java
com.couchbase.lite.Base64Test.java
com.couchbase.lite.BlobStoreWriterTest.java
com.couchbase.lite.CRUDOperationsTest.java
com.couchbase.lite.CacheTest.java
com.couchbase.lite.ChangesTest.java
com.couchbase.lite.CollationTest.java
com.couchbase.lite.DatabaseTest.java
com.couchbase.lite.DocumentTest.java
com.couchbase.lite.LitePerfTestCase.java
com.couchbase.lite.LiteTestCase.java
com.couchbase.lite.LiteTestContext.java
com.couchbase.lite.LocalDocsTest.java
com.couchbase.lite.ManagerTest.java
com.couchbase.lite.MiscTest.java
com.couchbase.lite.MultipartReaderTest.java
com.couchbase.lite.RevTreeTest.java
com.couchbase.lite.RevisionsTest.java
com.couchbase.lite.RouterTest.java
com.couchbase.lite.SequenceMapTest.java
com.couchbase.lite.ValidationsTest.java
com.couchbase.lite.ViewsTest.java
com.couchbase.lite.android.AndroidContext.java
com.couchbase.lite.android.AndroidLogger.java
com.couchbase.lite.android.AndroidNetworkReachabilityManager.java
com.couchbase.lite.android.AndroidSQLiteStorageEngineFactory.java
com.couchbase.lite.android.AndroidSQLiteStorageEngine.java
com.couchbase.lite.mockserver.MockBulkDocs.java
com.couchbase.lite.mockserver.MockChangesFeedNoResponse.java
com.couchbase.lite.mockserver.MockChangesFeed.java
com.couchbase.lite.mockserver.MockCheckpointGet.java
com.couchbase.lite.mockserver.MockCheckpointPut.java
com.couchbase.lite.mockserver.MockDispatcher.java
com.couchbase.lite.mockserver.MockDocumentBulkGet.java
com.couchbase.lite.mockserver.MockDocumentGet.java
com.couchbase.lite.mockserver.MockDocumentPut.java
com.couchbase.lite.mockserver.MockFacebookAuthPost.java
com.couchbase.lite.mockserver.MockHelper.java
com.couchbase.lite.mockserver.MockPreloadedPullTarget.java
com.couchbase.lite.mockserver.MockRevsDiff.java
com.couchbase.lite.mockserver.MockSessionGet.java
com.couchbase.lite.mockserver.SmartMockResponse.java
com.couchbase.lite.mockserver.WrappedSmartMockResponse.java
com.couchbase.lite.performance2.Test01_CreateDocs.java
com.couchbase.lite.performance2.Test02_CreateDocsUnoptimizedWay.java
com.couchbase.lite.performance2.Test03_CreateDocsWithAttachments.java
com.couchbase.lite.performance2.Test06_PullReplication.java
com.couchbase.lite.performance2.Test07_PushReplication.java
com.couchbase.lite.performance2.Test08_DocRevisions.java
com.couchbase.lite.performance2.Test09_LoadDB.java
com.couchbase.lite.performance2.Test10_DeleteDB.java
com.couchbase.lite.performance2.Test11_DeleteDocs.java
com.couchbase.lite.performance2.Test12_IndexView.java
com.couchbase.lite.performance2.Test13_QueryView.java
com.couchbase.lite.performance2.Test14_ReduceView.java
com.couchbase.lite.performance2.Test28_KeySizes.java
com.couchbase.lite.performance2.Test29_AllDocQuery.java
com.couchbase.lite.performance2.Test30_LiveQuery.java
com.couchbase.lite.performance2.Test31_CompactDB.java
com.couchbase.lite.performance.Test10_DeleteDB.java
com.couchbase.lite.performance.Test11_DeleteDocs.java
com.couchbase.lite.performance.Test12_IndexView.java
com.couchbase.lite.performance.Test13_QueryView.java
com.couchbase.lite.performance.Test14_ReduceView.java
com.couchbase.lite.performance.Test16_ParallelPushReplication.java
com.couchbase.lite.performance.Test1_CreateDocs.java
com.couchbase.lite.performance.Test2_CreateDocsUnoptimizedWay.java
com.couchbase.lite.performance.Test3_CreateDocsWithAttachments.java
com.couchbase.lite.performance.Test6_PushReplication.java
com.couchbase.lite.performance.Test7_PullReplication.java
com.couchbase.lite.performance.Test8_DocRevisions.java
com.couchbase.lite.performance.Test9_LoadDB.java
com.couchbase.lite.replicator.BulkDownloaderTest.java
com.couchbase.lite.replicator.ChangeTrackerTest.java
com.couchbase.lite.replicator.CustomizableMockHttpClient.java
com.couchbase.lite.replicator.ReplicationTest.java
com.couchbase.lite.replicator.ResponderChain.java
com.couchbase.lite.support.BatcherTest.java
com.couchbase.lite.support.JsonDocumentTest.java
com.couchbase.lite.support.PersistentCookieStoreTest.java
com.couchbase.lite.support.RemoteRequestTest.java
com.couchbase.touchdb.RevCollator.java
com.couchbase.touchdb.TDCollateJSON.java