Beispiel #1
0
        private void RunChangeTrackerTransientError(
            ChangeTrackerMode mode,
            Int32 errorCode,
            string statusMessage,
            Int32 numExpectedChangeCallbacks)
        {
            var changeTrackerFinishedSignal = new CountdownEvent(1);
            var changeReceivedSignal        = new CountdownEvent(numExpectedChangeCallbacks);
            var client = new ChangeTrackerTestClient(changeTrackerFinishedSignal, changeReceivedSignal);

            MockHttpRequestHandler.HttpResponseDelegate sentinal = RunChangeTrackerTransientErrorDefaultResponder();

            var responders = new List <MockHttpRequestHandler.HttpResponseDelegate>();

            responders.Add(RunChangeTrackerTransientErrorDefaultResponder());
            responders.Add(MockHttpRequestHandler.TransientErrorResponder(errorCode, statusMessage));

            MockHttpRequestHandler.HttpResponseDelegate chainResponder = (request) =>
            {
                if (responders.Count > 0)
                {
                    var responder = responders[0];
                    responders.RemoveAt(0);
                    return(responder(request));
                }

                return(sentinal(request));
            };

            var handler = client.HttpRequestHandler;

            handler.SetResponder("_changes", chainResponder);

            var testUrl       = GetReplicationURL();
            var scheduler     = new SingleTaskThreadpoolScheduler();
            var changeTracker = ChangeTrackerFactory.Create(new ChangeTrackerOptions {
                DatabaseUri      = testUrl,
                Mode             = mode,
                IncludeConflicts = false,
                Client           = client,
                RetryStrategy    = new ExponentialBackoffStrategy(2),
                WorkExecutor     = new TaskFactory(scheduler)
            });

            changeTracker.Start();

            var success = changeReceivedSignal.Wait(TimeSpan.FromSeconds(30));

            Assert.IsTrue(success);

            changeTracker.Stop();

            success = changeTrackerFinishedSignal.Wait(TimeSpan.FromSeconds(30));
            Assert.IsTrue(success);
        }
Beispiel #2
0
 private MockHttpRequestHandler.HttpResponseDelegate RunChangeTrackerTransientErrorDefaultResponder()
 {
     MockHttpRequestHandler.HttpResponseDelegate responder = (request) =>
     {
         var json = "{\"results\":[\n" +
                    "{\"seq\":\"1\",\"id\":\"doc1-138\",\"changes\":[{\"rev\":\"1-82d\"}]}],\n" +
                    "\"last_seq\":\"*:50\"}";
         return(MockHttpRequestHandler.GenerateHttpResponseMessage(System.Net.HttpStatusCode.OK, null, json));
     };
     return(responder);
 }
Beispiel #3
0
        private void ChangeTrackerTestWithMode(ChangeTrackerMode mode)
        {
            var changeTrackerFinishedSignal = new CountdownEvent(1);
            var changeReceivedSignal        = new CountdownEvent(1);
            var client = new ChangeTrackerTestClient(changeTrackerFinishedSignal, changeReceivedSignal);

            client.ReceivedChangeDelegate = (IDictionary <string, object> change) =>
            {
                Assert.IsTrue(change.ContainsKey("seq"));
                Assert.AreEqual("1", change["seq"]);
            };

            var handler = client.HttpRequestHandler;

            handler.SetResponder("_changes", (request) =>
            {
                var json = "{\"results\":[\n" +
                           "{\"seq\":\"1\",\"id\":\"doc1-138\",\"changes\":[{\"rev\":\"1-82d\"}]}],\n" +
                           "\"last_seq\":\"*:50\"}";
                return(MockHttpRequestHandler.GenerateHttpResponseMessage(System.Net.HttpStatusCode.OK, null, json));
            });

            var testUrl       = GetReplicationURL();
            var scheduler     = new SingleTaskThreadpoolScheduler();
            var remoteSession = new RemoteSession(new RemoteSessionContructorOptions {
                WorkExecutor = new TaskFactory(scheduler),
                BaseUrl      = testUrl
            });

            remoteSession.SetupHttpClientFactory(client.HttpClientFactory, database, "testwithmode");
            remoteSession.Setup(new ReplicationOptions());
            var changeTracker = ChangeTrackerFactory.Create(new ChangeTrackerOptions {
                DatabaseUri      = testUrl,
                Mode             = mode,
                IncludeConflicts = false,
                Client           = client,
                RetryStrategy    = new ExponentialBackoffStrategy(2),
                WorkExecutor     = new TaskFactory(scheduler),
                RemoteSession    = remoteSession
            });

            changeTracker.ActiveOnly = true;
            changeTracker.Start();

            var success = changeReceivedSignal.Wait(TimeSpan.FromSeconds(30));

            Assert.IsTrue(success);

            changeTracker.Stop();

            success = changeTrackerFinishedSignal.Wait(TimeSpan.FromSeconds(30));
            Assert.IsTrue(success);
        }
Beispiel #4
0
        private void RunChangeTrackerTransientError(
            ChangeTrackerMode mode,
            Int32 errorCode,
            string statusMessage,
            Int32 numExpectedChangeCallbacks)
        {
            var changeTrackerFinishedSignal = new CountDownLatch(1);
            var changeReceivedSignal        = new CountDownLatch(numExpectedChangeCallbacks);
            var client = new ChangeTrackerTestClient(changeTrackerFinishedSignal, changeReceivedSignal);

            MockHttpRequestHandler.HttpResponseDelegate sentinal = RunChangeTrackerTransientErrorDefaultResponder();

            var responders = new List <MockHttpRequestHandler.HttpResponseDelegate>();

            responders.Add(RunChangeTrackerTransientErrorDefaultResponder());
            responders.Add(MockHttpRequestHandler.TransientErrorResponder(errorCode, statusMessage));

            MockHttpRequestHandler.HttpResponseDelegate chainResponder = (request) =>
            {
                if (responders.Count > 0)
                {
                    var responder = responders[0];
                    responders.RemoveAt(0);
                    return(responder(request));
                }

                return(sentinal(request));
            };

            var handler = client.HttpRequestHandler;

            handler.SetResponder("_changes", chainResponder);

            var testUrl       = GetReplicationURL();
            var scheduler     = new SingleTaskThreadpoolScheduler();
            var changeTracker = new ChangeTracker(testUrl, mode, 0, false, client, new TaskFactory(scheduler));

            changeTracker.UsePost = IsSyncGateway(testUrl);
            changeTracker.Start();

            var success = changeReceivedSignal.Await(TimeSpan.FromSeconds(30));

            Assert.IsTrue(success);

            changeTracker.Stop();

            success = changeTrackerFinishedSignal.Await(TimeSpan.FromSeconds(30));
            Assert.IsTrue(success);
        }
Beispiel #5
0
        public void TestAllLeafRevisionsArePushed()
        {
            var httpClientFactory = new MockHttpClientFactory();
            var httpHandler       = httpClientFactory.HttpHandler;

            httpHandler.AddResponderRevDiffsAllMissing();
            httpHandler.AddResponderFakeLocalDocumentUpdate404();
            httpHandler.ResponseDelayMilliseconds = 250;
            manager.DefaultHttpClientFactory      = httpClientFactory;

            var doc   = database.CreateDocument();
            var rev1a = doc.CreateRevision().Save();
            var rev2a = rev1a.CreateRevision().Save();
            var rev3a = rev2a.CreateRevision().Save();

            // delete the branch we've been using, then create a new one to replace it
            var rev4a = rev3a.DeleteDocument();
            var rev2b = rev1a.CreateRevision().Save(true);

            Assert.AreEqual(rev2b.Id, doc.CurrentRevisionId);

            // sync with remote DB -- should push both leaf revisions
            var pusher = database.CreatePushReplication(GetReplicationURL());

            RunReplication(pusher);
            Assert.IsNull(pusher.LastError);

            var foundRevsDiff    = false;
            var capturedRequests = httpHandler.CapturedRequests;

            foreach (var httpRequest in capturedRequests)
            {
                var uriString = httpRequest.RequestUri.ToString();
                if (uriString.EndsWith("_revs_diff", StringComparison.Ordinal))
                {
                    foundRevsDiff = true;
                    var jsonMap     = MockHttpRequestHandler.GetJsonMapFromRequest(httpRequest);
                    var revisionIds = ((JArray)jsonMap.Get(doc.Id)).Values <string>().ToList();
                    Assert.AreEqual(2, revisionIds.Count);
                    Assert.IsTrue(revisionIds.Contains(rev4a.Id));
                    Assert.IsTrue(revisionIds.Contains(rev2b.Id));
                }
            }

            Assert.IsTrue(foundRevsDiff);
        }
Beispiel #6
0
        public async Task SendAsync_ExistsInCassette_DoesNotCallInnerHttpHandler()
        {
            var cassette = new Cassette();
            var record   = new CassetteRecord(
                new CassetteRecordRequest(
                    HttpMethod.Get.Method,
                    new Uri("http://*****:*****@"{""a"": 1, ""b"": 2}"));

            cassette.Add(record);

            var mockHttpHandler         = new MockHttpRequestHandler();
            var tryReplayMessageHandler = new PublicTryReplayHttpMessageHandler(cassette, mockHttpHandler);

            var request = new HttpRequestMessage
            {
                Method     = HttpMethod.Get,
                RequestUri = new Uri("http://localhost:8080/test"),
            };
            var response = await tryReplayMessageHandler.SendAsync(request);

            Assert.That(mockHttpHandler.Invoked, Is.False);

            Assert.That(response.Version, Is.EqualTo(record.Response.Version));
            Assert.That(response.StatusCode, Is.EqualTo((HttpStatusCode)record.Response.StatusCode));
            Assert.That(response.ReasonPhrase, Is.EqualTo(record.Response.StatusMessage));
            Assert.That(response.RequestMessage, Is.Not.Null);
            Assert.That(response.Headers.GetValues("Server"), Is.EqualTo(new[] { record.Response.Headers["Server"] }));
        }
Beispiel #7
0
        public async Task SendAsync_DoesNotExistInCassette_CallsInnerHttpHandler()
        {
            var cassette = new Cassette();

            var mockHttpHandler         = new MockHttpRequestHandler();
            var tryReplayMessageHandler = new PublicTryReplayHttpMessageHandler(cassette, mockHttpHandler);

            var request = new HttpRequestMessage
            {
                Method     = HttpMethod.Get,
                RequestUri = new Uri("http://localhost:8080/test"),
            };
            var response = await tryReplayMessageHandler.SendAsync(request);

            Assert.That(mockHttpHandler.Invoked, Is.True);

            Assert.That(response.Version, Is.EqualTo(new Version(1, 1)));
            Assert.That(response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
            Assert.That(response.ReasonPhrase, Is.EqualTo("OK"));
            Assert.That(response.RequestMessage, Is.Not.Null);
            Assert.That(response.Headers.GetValues("Server"), Is.EqualTo(new[] { "Test-Server" }));
        }
Beispiel #8
0
        private void ChangeTrackerTestWithMode(ChangeTrackerMode mode)
        {
            var changeTrackerFinishedSignal = new CountDownLatch(1);
            var changeReceivedSignal        = new CountDownLatch(1);
            var client = new ChangeTrackerTestClient(changeTrackerFinishedSignal, changeReceivedSignal);

            client.ReceivedChangeDelegate = (IDictionary <string, object> change) =>
            {
                Assert.IsTrue(change.ContainsKey("seq"));
                Assert.AreEqual("1", change["seq"]);
            };

            var handler = client.HttpRequestHandler;

            handler.SetResponder("_changes", (request) =>
            {
                var json = "{\"results\":[\n" +
                           "{\"seq\":\"1\",\"id\":\"doc1-138\",\"changes\":[{\"rev\":\"1-82d\"}]}],\n" +
                           "\"last_seq\":\"*:50\"}";
                return(MockHttpRequestHandler.GenerateHttpResponseMessage(System.Net.HttpStatusCode.OK, null, json));
            });

            var testUrl       = GetReplicationURL();
            var scheduler     = new SingleTaskThreadpoolScheduler();
            var changeTracker = new ChangeTracker(testUrl, mode, 0, false, client, new TaskFactory(scheduler));

            changeTracker.UsePost = IsSyncGateway(testUrl);
            changeTracker.Start();

            var success = changeReceivedSignal.Await(TimeSpan.FromSeconds(30));

            Assert.IsTrue(success);

            changeTracker.Stop();

            success = changeTrackerFinishedSignal.Await(TimeSpan.FromSeconds(30));
            Assert.IsTrue(success);
        }
Beispiel #9
0
        public void TestPushPurgedDoc()
        {
            var numBulkDocRequests = 0;
            HttpRequestMessage lastBulkDocsRequest = null;

            var doc = CreateDocumentWithProperties(
                database,
                new Dictionary <string, object>
            {
                { "testName", "testPurgeDocument" }
            }
                );

            Assert.IsNotNull(doc);

            var remote  = GetReplicationURL();
            var factory = new MockHttpClientFactory();

            factory.HttpHandler.ClearResponders();
            factory.HttpHandler.AddResponderRevDiffsAllMissing();
            factory.HttpHandler.AddResponderFakeLocalDocumentUpdate404();
            factory.HttpHandler.AddResponderFakeBulkDocs();
            manager.DefaultHttpClientFactory = factory;

            var pusher = database.CreatePushReplication(remote);

            pusher.Continuous = true;

            var replicationCaughtUpSignal = new CountdownEvent(1);

            pusher.Changed += (sender, e) =>
            {
                var changesCount          = e.Source.ChangesCount;
                var completedChangesCount = e.Source.CompletedChangesCount;
                var msg = "changes: {0} completed changes: {1}".Fmt(changesCount, completedChangesCount);
                Log.D(Tag, msg);
                if (changesCount == completedChangesCount &&
                    changesCount != 0 &&
                    replicationCaughtUpSignal.CurrentCount > 0)
                {
                    replicationCaughtUpSignal.Signal();
                }
            };
            pusher.Start();

            // wait until that doc is pushed
            var didNotTimeOut = replicationCaughtUpSignal.Wait(TimeSpan.FromSeconds(5));

            Assert.IsTrue(didNotTimeOut);

            // at this point, we should have captured exactly 1 bulk docs request
            numBulkDocRequests = 0;

            var handler = factory.HttpHandler;

            foreach (var capturedRequest in handler.CapturedRequests)
            {
                if (capturedRequest.Method == HttpMethod.Post && capturedRequest.RequestUri.AbsoluteUri.EndsWith("_bulk_docs", StringComparison.Ordinal))
                {
                    lastBulkDocsRequest = capturedRequest;
                    numBulkDocRequests++;
                }
            }

            Assert.AreEqual(1, numBulkDocRequests);

            // that bulk docs request should have the "start" key under its _revisions
            var jsonMap   = MockHttpRequestHandler.GetJsonMapFromRequest(lastBulkDocsRequest);
            var docs      = ((JArray)jsonMap.Get("docs")).ToObject <IList <IDictionary <string, object> > >();
            var onlyDoc   = docs[0];
            var revisions = ((JObject)onlyDoc.Get("_revisions")).ToObject <IDictionary <string, object> >();

            Assert.IsTrue(revisions.ContainsKey("start"));

            // Reset for the next attempt.
            handler.ClearCapturedRequests();

            // now add a new revision, which will trigger the pusher to try to push it
            var properties = new Dictionary <string, object>();

            properties.Put("testName2", "update doc");

            var unsavedRevision = doc.CreateRevision();

            unsavedRevision.SetUserProperties(properties);
            unsavedRevision.Save();

            // but then immediately purge it
            doc.Purge();

            // wait for a while to give the replicator a chance to push it
            // (it should not actually push anything)
            System.Threading.Thread.Sleep(5 * 1000);

            // we should not have gotten any more _bulk_docs requests, because
            // the replicator should not have pushed anything else.
            // (in the case of the bug, it was trying to push the purged revision)
            numBulkDocRequests = 0;
            foreach (var capturedRequest in handler.CapturedRequests)
            {
                if (capturedRequest.Method == HttpMethod.Post && capturedRequest.RequestUri.AbsoluteUri.EndsWith("_bulk_docs", StringComparison.Ordinal))
                {
                    numBulkDocRequests++;
                }
            }

            Assert.AreEqual(1, numBulkDocRequests);
            pusher.Stop();
        }
Beispiel #10
0
        public void TestPushReplicationCanMissDocs()
        {
            Assert.AreEqual(0, database.LastSequenceNumber);

            var properties1 = new Dictionary <string, object>();

            properties1["doc1"] = "testPushReplicationCanMissDocs";
            var doc1 = CreateDocumentWithProperties(database, properties1);

            var properties2 = new Dictionary <string, object>();

            properties2["doc2"] = "testPushReplicationCanMissDocs";
            var doc2 = CreateDocumentWithProperties(database, properties2);

            var doc2UnsavedRev   = doc2.CreateRevision();
            var attachmentStream = GetAsset("attachment.png");

            doc2UnsavedRev.SetAttachment("attachment.png", "image/png", attachmentStream);
            var doc2Rev = doc2UnsavedRev.Save();

            Assert.IsNotNull(doc2Rev);

            var httpClientFactory = new MockHttpClientFactory();

            manager.DefaultHttpClientFactory = httpClientFactory;

            var httpHandler = httpClientFactory.HttpHandler;

            httpHandler.AddResponderFakeLocalDocumentUpdate404();

            var json = "{\"error\":\"not_found\",\"reason\":\"missing\"}";

            MockHttpRequestHandler.HttpResponseDelegate bulkDocsResponder = (request) =>
            {
                return(MockHttpRequestHandler.GenerateHttpResponseMessage(HttpStatusCode.NotFound, null, json));
            };
            httpHandler.SetResponder("_bulk_docs", bulkDocsResponder);

            MockHttpRequestHandler.HttpResponseDelegate doc2Responder = (request) =>
            {
                var responseObject = new Dictionary <string, object>();
                responseObject["id"]  = doc2.Id;
                responseObject["ok"]  = true;
                responseObject["rev"] = doc2.CurrentRevisionId;
                return(MockHttpRequestHandler.GenerateHttpResponseMessage(responseObject));
            };
            httpHandler.SetResponder(doc2.Id, bulkDocsResponder);

            var replicationDoneSignal = new CountDownLatch(1);
            var observer = new ReplicationObserver(replicationDoneSignal);
            var pusher   = database.CreatePushReplication(GetReplicationURL());

            pusher.Changed += observer.Changed;
            pusher.Start();

            var success = replicationDoneSignal.Await(TimeSpan.FromSeconds(5));

            Assert.IsTrue(success);

            Assert.IsNotNull(pusher.LastError);

            System.Threading.Thread.Sleep(TimeSpan.FromMilliseconds(500));

            var localLastSequence = database.LastSequenceWithCheckpointId(pusher.RemoteCheckpointDocID());

            Log.D(Tag, "dtabase.lastSequenceWithCheckpointId(): " + localLastSequence);
            Log.D(Tag, "doc2.getCUrrentRevision().getSequence(): " + doc2.CurrentRevision.Sequence);

            // Since doc1 failed, the database should _not_ have had its lastSequence bumped to doc2's sequence number.
            // If it did, it's bug: github.com/couchbase/couchbase-lite-java-core/issues/95
            Assert.IsFalse(doc2.CurrentRevision.Sequence.ToString().Equals(localLastSequence));
            Assert.IsNull(localLastSequence);
            Assert.IsTrue(doc2.CurrentRevision.Sequence > 0);
        }