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); }
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); }
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); }
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); }
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); }
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"] })); }
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" })); }
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); }
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(); }
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); }