/// <summary>Regression test for https://github.com/couchbase/couchbase-lite-java-core/issues/72 /// </summary> /// <exception cref="System.Exception"></exception> public virtual void TestPusherBatching() { // create a bunch (INBOX_CAPACITY * 2) local documents int numDocsToSend = Replication.InboxCapacity * 2; for (int i = 0; i < numDocsToSend; i++) { IDictionary<string, object> properties = new Dictionary<string, object>(); properties.Put("testPusherBatching", i); CreateDocumentWithProperties(database, properties); } // kick off a one time push replication to a mock CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); HttpClientFactory mockHttpClientFactory = MockFactoryFactory(mockHttpClient); Uri remote = GetReplicationURL(); manager.SetDefaultHttpClientFactory(mockHttpClientFactory); Replication pusher = database.CreatePushReplication(remote); RunReplication(pusher); NUnit.Framework.Assert.IsNull(pusher.GetLastError()); int numDocsSent = 0; // verify that only INBOX_SIZE documents are included in any given bulk post request IList<HttpWebRequest> capturedRequests = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest capturedRequest in capturedRequests) { if (capturedRequest is HttpPost) { HttpPost capturedPostRequest = (HttpPost)capturedRequest; if (capturedPostRequest.GetURI().GetPath().EndsWith("_bulk_docs")) { ArrayList docs = CustomizableMockHttpClient.ExtractDocsFromBulkDocsPost(capturedRequest ); string msg = "# of bulk docs pushed should be <= INBOX_CAPACITY"; NUnit.Framework.Assert.IsTrue(msg, docs.Count <= Replication.InboxCapacity); numDocsSent += docs.Count; } } } NUnit.Framework.Assert.AreEqual(numDocsToSend, numDocsSent); }
/// <summary>https://github.com/couchbase/couchbase-lite-java-core/issues/188</summary> /// <exception cref="System.Exception"></exception> public virtual void TestServerDoesNotSupportMultipart() { NUnit.Framework.Assert.AreEqual(0, database.GetLastSequenceNumber()); IDictionary<string, object> properties1 = new Dictionary<string, object>(); properties1.Put("dynamic", 1); Document doc = CreateDocWithProperties(properties1); SavedRevision doc1Rev = doc.GetCurrentRevision(); // Add attachment to document UnsavedRevision doc2UnsavedRev = doc.CreateRevision(); InputStream attachmentStream = GetAsset("attachment.png"); doc2UnsavedRev.SetAttachment("attachment.png", "image/png", attachmentStream); SavedRevision doc2Rev = doc2UnsavedRev.Save(); NUnit.Framework.Assert.IsNotNull(doc2Rev); CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); Queue<CustomizableMockHttpClient.Responder> responders = new List<CustomizableMockHttpClient.Responder >(); //first http://url/db/foo (foo==docid) //Reject multipart PUT with response code 415 responders.AddItem(new _Responder_1691()); // second http://url/db/foo (foo==docid) // second call should be plain json, return good response responders.AddItem(new _Responder_1701(doc)); ResponderChain responderChain = new ResponderChain(responders); mockHttpClient.SetResponder(doc.GetId(), responderChain); // create replication and add observer manager.SetDefaultHttpClientFactory(MockFactoryFactory(mockHttpClient)); Replication pusher = database.CreatePushReplication(GetReplicationURL()); RunReplication(pusher); IList<HttpWebRequest> captured = mockHttpClient.GetCapturedRequests(); int entityIndex = 0; foreach (HttpWebRequest httpRequest in captured) { // verify that there are no PUT requests with attachments if (httpRequest is HttpPut) { HttpPut httpPut = (HttpPut)httpRequest; HttpEntity entity = httpPut.GetEntity(); if (entityIndex++ == 0) { NUnit.Framework.Assert.IsTrue("PUT request with attachment is not multipart", entity is MultipartEntity); } else { NUnit.Framework.Assert.IsFalse("PUT request with attachment is multipart", entity is MultipartEntity); } } } }
/// <exception cref="System.Exception"></exception> public virtual void DisabledTestCheckpointingWithServerError() { string remoteCheckpointDocId; string lastSequenceWithCheckpointIdInitial; string lastSequenceWithCheckpointIdFinal; Uri remote = GetReplicationURL(); // add docs string docIdTimestamp = System.Convert.ToString(Runtime.CurrentTimeMillis()); CreateDocumentsForPushReplication(docIdTimestamp); // do push replication against mock replicator that fails to save remote checkpoint CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); manager.SetDefaultHttpClientFactory(MockFactoryFactory(mockHttpClient)); Replication pusher = database.CreatePushReplication(remote); remoteCheckpointDocId = pusher.RemoteCheckpointDocID(); lastSequenceWithCheckpointIdInitial = database.LastSequenceWithCheckpointId(remoteCheckpointDocId ); RunReplication(pusher); IList<HttpWebRequest> capturedRequests = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest capturedRequest in capturedRequests) { if (capturedRequest is HttpPost) { HttpPost capturedPostRequest = (HttpPost)capturedRequest; } } // sleep to allow for any "post-finished" activities on the replicator related to checkpointing Sharpen.Thread.Sleep(2000); // make sure local checkpoint is not updated lastSequenceWithCheckpointIdFinal = database.LastSequenceWithCheckpointId(remoteCheckpointDocId ); string msg = "since the mock replicator rejected the PUT to _local/remoteCheckpointDocId, we " + "would expect lastSequenceWithCheckpointIdInitial == lastSequenceWithCheckpointIdFinal"; NUnit.Framework.Assert.AreEqual(msg, lastSequenceWithCheckpointIdFinal, lastSequenceWithCheckpointIdInitial ); Log.D(Tag, "replication done"); }
// Reproduces issue #167 // https://github.com/couchbase/couchbase-lite-android/issues/167 /// <exception cref="System.Exception"></exception> public virtual void TestPushPurgedDoc() { int numBulkDocRequests = 0; HttpPost lastBulkDocsRequest = null; IDictionary<string, object> properties = new Dictionary<string, object>(); properties.Put("testName", "testPurgeDocument"); Document doc = CreateDocumentWithProperties(database, properties); NUnit.Framework.Assert.IsNotNull(doc); CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderRevDiffsAllMissing(); mockHttpClient.SetResponseDelayMilliseconds(250); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); HttpClientFactory mockHttpClientFactory = new _HttpClientFactory_169(mockHttpClient ); Uri remote = GetReplicationURL(); manager.SetDefaultHttpClientFactory(mockHttpClientFactory); Replication pusher = database.CreatePushReplication(remote); pusher.SetContinuous(true); CountDownLatch replicationCaughtUpSignal = new CountDownLatch(1); pusher.AddChangeListener(new _ChangeListener_199(replicationCaughtUpSignal)); pusher.Start(); // wait until that doc is pushed bool didNotTimeOut = replicationCaughtUpSignal.Await(60, TimeUnit.Seconds); NUnit.Framework.Assert.IsTrue(didNotTimeOut); // at this point, we should have captured exactly 1 bulk docs request numBulkDocRequests = 0; foreach (HttpWebRequest capturedRequest in mockHttpClient.GetCapturedRequests()) { if (capturedRequest is HttpPost && ((HttpPost)capturedRequest).GetURI().ToString( ).EndsWith("_bulk_docs")) { lastBulkDocsRequest = (HttpPost)capturedRequest; numBulkDocRequests += 1; } } NUnit.Framework.Assert.AreEqual(1, numBulkDocRequests); // that bulk docs request should have the "start" key under its _revisions IDictionary<string, object> jsonMap = CustomizableMockHttpClient.GetJsonMapFromRequest ((HttpPost)lastBulkDocsRequest); IList docs = (IList)jsonMap.Get("docs"); IDictionary<string, object> onlyDoc = (IDictionary)docs[0]; IDictionary<string, object> revisions = (IDictionary)onlyDoc.Get("_revisions"); NUnit.Framework.Assert.IsTrue(revisions.ContainsKey("start")); // now add a new revision, which will trigger the pusher to try to push it properties = new Dictionary<string, object>(); properties.Put("testName2", "update doc"); UnsavedRevision 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) Sharpen.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 (HttpWebRequest capturedRequest_1 in mockHttpClient.GetCapturedRequests()) { if (capturedRequest_1 is HttpPost && ((HttpPost)capturedRequest_1).GetURI().ToString ().EndsWith("_bulk_docs")) { numBulkDocRequests += 1; } } NUnit.Framework.Assert.AreEqual(1, numBulkDocRequests); pusher.Stop(); }
/// <summary>https://github.com/couchbase/couchbase-lite-android/issues/66</summary> /// <exception cref="System.Exception"></exception> public virtual void TestPushUpdatedDocWithoutReSendingAttachments() { NUnit.Framework.Assert.AreEqual(0, database.GetLastSequenceNumber()); IDictionary<string, object> properties1 = new Dictionary<string, object>(); properties1.Put("dynamic", 1); Document doc = CreateDocWithProperties(properties1); SavedRevision doc1Rev = doc.GetCurrentRevision(); // Add attachment to document UnsavedRevision doc2UnsavedRev = doc.CreateRevision(); InputStream attachmentStream = GetAsset("attachment.png"); doc2UnsavedRev.SetAttachment("attachment.png", "image/png", attachmentStream); SavedRevision doc2Rev = doc2UnsavedRev.Save(); NUnit.Framework.Assert.IsNotNull(doc2Rev); CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); // http://url/db/foo (foo==docid) mockHttpClient.SetResponder(doc.GetId(), new _Responder_1593(doc)); // create replication and add observer manager.SetDefaultHttpClientFactory(MockFactoryFactory(mockHttpClient)); Replication pusher = database.CreatePushReplication(GetReplicationURL()); RunReplication(pusher); IList<HttpWebRequest> captured = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest httpRequest in captured) { // verify that there are no PUT requests with attachments if (httpRequest is HttpPut) { HttpPut httpPut = (HttpPut)httpRequest; HttpEntity entity = httpPut.GetEntity(); } } //assertFalse("PUT request with updated doc properties contains attachment", entity instanceof MultipartEntity); mockHttpClient.ClearCapturedRequests(); Document oldDoc = database.GetDocument(doc.GetId()); UnsavedRevision aUnsavedRev = oldDoc.CreateRevision(); IDictionary<string, object> prop = new Dictionary<string, object>(); prop.PutAll(oldDoc.GetProperties()); prop.Put("dynamic", (int)oldDoc.GetProperty("dynamic") + 1); aUnsavedRev.SetProperties(prop); SavedRevision savedRev = aUnsavedRev.Save(); mockHttpClient.SetResponder(doc.GetId(), new _Responder_1630(doc, savedRev)); string json = string.Format("{\"%s\":{\"missing\":[\"%s\"],\"possible_ancestors\":[\"%s\",\"%s\"]}}" , doc.GetId(), savedRev.GetId(), doc1Rev.GetId(), doc2Rev.GetId()); mockHttpClient.SetResponder("_revs_diff", new _Responder_1642(mockHttpClient, json )); pusher = database.CreatePushReplication(GetReplicationURL()); RunReplication(pusher); captured = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest httpRequest_1 in captured) { // verify that there are no PUT requests with attachments if (httpRequest_1 is HttpPut) { HttpPut httpPut = (HttpPut)httpRequest_1; HttpEntity entity = httpPut.GetEntity(); NUnit.Framework.Assert.IsFalse("PUT request with updated doc properties contains attachment" , entity is MultipartEntity); } } }
/// <summary>https://github.com/couchbase/couchbase-lite-java-core/issues/95</summary> /// <exception cref="System.Exception"></exception> public virtual void TestPushReplicationCanMissDocs() { NUnit.Framework.Assert.AreEqual(0, database.GetLastSequenceNumber()); IDictionary<string, object> properties1 = new Dictionary<string, object>(); properties1.Put("doc1", "testPushReplicationCanMissDocs"); Document doc1 = CreateDocWithProperties(properties1); IDictionary<string, object> properties2 = new Dictionary<string, object>(); properties1.Put("doc2", "testPushReplicationCanMissDocs"); Document doc2 = CreateDocWithProperties(properties2); UnsavedRevision doc2UnsavedRev = doc2.CreateRevision(); InputStream attachmentStream = GetAsset("attachment.png"); doc2UnsavedRev.SetAttachment("attachment.png", "image/png", attachmentStream); SavedRevision doc2Rev = doc2UnsavedRev.Save(); NUnit.Framework.Assert.IsNotNull(doc2Rev); CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); mockHttpClient.SetResponder("_bulk_docs", new _Responder_1506()); mockHttpClient.SetResponder(doc2.GetId(), new _Responder_1514(doc2)); // create a replication obeserver to wait until replication finishes CountDownLatch replicationDoneSignal = new CountDownLatch(1); LiteTestCase.ReplicationFinishedObserver replicationFinishedObserver = new LiteTestCase.ReplicationFinishedObserver (replicationDoneSignal); // create replication and add observer manager.SetDefaultHttpClientFactory(MockFactoryFactory(mockHttpClient)); Replication pusher = database.CreatePushReplication(GetReplicationURL()); pusher.AddChangeListener(replicationFinishedObserver); // save the checkpoint id for later usage string checkpointId = pusher.RemoteCheckpointDocID(); // kick off the replication pusher.Start(); // wait for it to finish bool success = replicationDoneSignal.Await(60, TimeUnit.Seconds); NUnit.Framework.Assert.IsTrue(success); Log.D(Tag, "replicationDoneSignal finished"); // we would expect it to have recorded an error because one of the docs (the one without the attachment) // will have failed. NUnit.Framework.Assert.IsNotNull(pusher.GetLastError()); // workaround for the fact that the replicationDoneSignal.wait() call will unblock before all // the statements in Replication.stopped() have even had a chance to execute. // (specifically the ones that come after the call to notifyChangeListeners()) Sharpen.Thread.Sleep(500); string localLastSequence = database.LastSequenceWithCheckpointId(checkpointId); Log.D(Tag, "database.lastSequenceWithCheckpointId(): " + localLastSequence); Log.D(Tag, "doc2.getCurrentRevision().getSequence(): " + doc2.GetCurrentRevision( ).GetSequence()); string msg = "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"; NUnit.Framework.Assert.IsFalse(msg, System.Convert.ToString(doc2.GetCurrentRevision ().GetSequence()).Equals(localLastSequence)); NUnit.Framework.Assert.IsNull(localLastSequence); NUnit.Framework.Assert.IsTrue(doc2.GetCurrentRevision().GetSequence() > 0); }
/// <summary>https://github.com/couchbase/couchbase-lite-android/issues/247</summary> /// <exception cref="System.Exception"></exception> public virtual void RunPushReplicationWithTransientError(int statusCode, string statusMsg , bool expectReplicatorError) { IDictionary<string, object> properties1 = new Dictionary<string, object>(); properties1.Put("doc1", "testPushReplicationTransientError"); CreateDocWithProperties(properties1); CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); CustomizableMockHttpClient.Responder sentinal = CustomizableMockHttpClient.FakeBulkDocsResponder (); Queue<CustomizableMockHttpClient.Responder> responders = new List<CustomizableMockHttpClient.Responder >(); responders.AddItem(CustomizableMockHttpClient.TransientErrorResponder(statusCode, statusMsg)); ResponderChain responderChain = new ResponderChain(responders, sentinal); mockHttpClient.SetResponder("_bulk_docs", responderChain); // create a replication observer to wait until replication finishes CountDownLatch replicationDoneSignal = new CountDownLatch(1); LiteTestCase.ReplicationFinishedObserver replicationFinishedObserver = new LiteTestCase.ReplicationFinishedObserver (replicationDoneSignal); // create replication and add observer manager.SetDefaultHttpClientFactory(MockFactoryFactory(mockHttpClient)); Replication pusher = database.CreatePushReplication(GetReplicationURL()); pusher.AddChangeListener(replicationFinishedObserver); // save the checkpoint id for later usage string checkpointId = pusher.RemoteCheckpointDocID(); // kick off the replication pusher.Start(); // wait for it to finish bool success = replicationDoneSignal.Await(60, TimeUnit.Seconds); NUnit.Framework.Assert.IsTrue(success); Log.D(Tag, "replicationDoneSignal finished"); if (expectReplicatorError == true) { NUnit.Framework.Assert.IsNotNull(pusher.GetLastError()); } else { NUnit.Framework.Assert.IsNull(pusher.GetLastError()); } // workaround for the fact that the replicationDoneSignal.wait() call will unblock before all // the statements in Replication.stopped() have even had a chance to execute. // (specifically the ones that come after the call to notifyChangeListeners()) Sharpen.Thread.Sleep(500); string localLastSequence = database.LastSequenceWithCheckpointId(checkpointId); if (expectReplicatorError == true) { NUnit.Framework.Assert.IsNull(localLastSequence); } else { NUnit.Framework.Assert.IsNotNull(localLastSequence); } }
/// <exception cref="System.Exception"></exception> public virtual void TestOnlineOfflinePusher() { Uri remote = GetReplicationURL(); // mock sync gateway CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); mockHttpClient.AddResponderRevDiffsSmartResponder(); HttpClientFactory mockHttpClientFactory = MockFactoryFactory(mockHttpClient); manager.SetDefaultHttpClientFactory(mockHttpClientFactory); // create a replication observer CountDownLatch replicationDoneSignal = new CountDownLatch(1); LiteTestCase.ReplicationFinishedObserver replicationFinishedObserver = new LiteTestCase.ReplicationFinishedObserver (replicationDoneSignal); // create a push replication Replication pusher = database.CreatePushReplication(remote); Log.D(Database.Tag, "created pusher: " + pusher); pusher.AddChangeListener(replicationFinishedObserver); pusher.SetContinuous(true); pusher.Start(); for (int i = 0; i < 5; i++) { Log.D(Database.Tag, "testOnlineOfflinePusher, i: " + i); string docFieldName = "testOnlineOfflinePusher" + i; // put the replication offline PutReplicationOffline(pusher); // add a response listener to wait for a bulk_docs request from the pusher CountDownLatch gotBulkDocsRequest = new CountDownLatch(1); CustomizableMockHttpClient.ResponseListener bulkDocsListener = new _ResponseListener_1334 (docFieldName, gotBulkDocsRequest); mockHttpClient.AddResponseListener(bulkDocsListener); // add a document string docFieldVal = "foo" + i; IDictionary<string, object> properties = new Dictionary<string, object>(); properties.Put(docFieldName, docFieldVal); CreateDocumentWithProperties(database, properties); // put the replication online, which should trigger it to send outgoing bulk_docs request PutReplicationOnline(pusher); // wait until we get a bulk docs request Log.D(Database.Tag, "waiting for bulk docs request with " + docFieldName); bool succeeded = gotBulkDocsRequest.Await(90, TimeUnit.Seconds); NUnit.Framework.Assert.IsTrue(succeeded); Log.D(Database.Tag, "got bulk docs request with " + docFieldName); mockHttpClient.RemoveResponseListener(bulkDocsListener); mockHttpClient.ClearCapturedRequests(); } Log.D(Database.Tag, "calling pusher.stop()"); pusher.Stop(); Log.D(Database.Tag, "called pusher.stop()"); // wait for replication to finish Log.D(Database.Tag, "waiting for replicationDoneSignal"); bool didNotTimeOut = replicationDoneSignal.Await(90, TimeUnit.Seconds); Log.D(Database.Tag, "done waiting for replicationDoneSignal. didNotTimeOut: " + didNotTimeOut); NUnit.Framework.Assert.IsTrue(didNotTimeOut); NUnit.Framework.Assert.IsFalse(pusher.IsRunning()); }
/// <summary>Regression test for issue couchbase/couchbase-lite-android#174</summary> /// <exception cref="System.Exception"></exception> public virtual void TestAllLeafRevisionsArePushed() { CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderRevDiffsAllMissing(); mockHttpClient.SetResponseDelayMilliseconds(250); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); HttpClientFactory mockHttpClientFactory = new _HttpClientFactory_1165(mockHttpClient ); manager.SetDefaultHttpClientFactory(mockHttpClientFactory); Document doc = database.CreateDocument(); SavedRevision rev1a = doc.CreateRevision().Save(); SavedRevision rev2a = CreateRevisionWithRandomProps(rev1a, false); SavedRevision rev3a = CreateRevisionWithRandomProps(rev2a, false); // delete the branch we've been using, then create a new one to replace it SavedRevision rev4a = rev3a.DeleteDocument(); SavedRevision rev2b = CreateRevisionWithRandomProps(rev1a, true); NUnit.Framework.Assert.AreEqual(rev2b.GetId(), doc.GetCurrentRevisionId()); // sync with remote DB -- should push both leaf revisions Replication push = database.CreatePushReplication(GetReplicationURL()); RunReplication(push); NUnit.Framework.Assert.IsNull(push.GetLastError()); // find the _revs_diff captured request and decode into json bool foundRevsDiff = false; IList<HttpWebRequest> captured = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest httpRequest in captured) { if (httpRequest is HttpPost) { HttpPost httpPost = (HttpPost)httpRequest; if (httpPost.GetURI().ToString().EndsWith("_revs_diff")) { foundRevsDiff = true; IDictionary<string, object> jsonMap = CustomizableMockHttpClient.GetJsonMapFromRequest (httpPost); // assert that it contains the expected revisions IList<string> revisionIds = (IList)jsonMap.Get(doc.GetId()); NUnit.Framework.Assert.AreEqual(2, revisionIds.Count); NUnit.Framework.Assert.IsTrue(revisionIds.Contains(rev4a.GetId())); NUnit.Framework.Assert.IsTrue(revisionIds.Contains(rev2b.GetId())); } } } NUnit.Framework.Assert.IsTrue(foundRevsDiff); }
/// <exception cref="System.Exception"></exception> public virtual void TestOnlineOfflinePusher() { Uri remote = GetReplicationURL(); // mock sync gateway CustomizableMockHttpClient mockHttpClient = new CustomizableMockHttpClient(); mockHttpClient.AddResponderFakeLocalDocumentUpdate404(); mockHttpClient.AddResponderRevDiffsSmartResponder(); HttpClientFactory mockHttpClientFactory = MockFactoryFactory(mockHttpClient); manager.SetDefaultHttpClientFactory(mockHttpClientFactory); // create a push replication Replication pusher = database.CreatePushReplication(remote); Log.D(Database.Tag, "created pusher: " + pusher); pusher.SetContinuous(true); pusher.Start(); for (int i = 0; i < 5; i++) { Log.D(Database.Tag, "testOnlineOfflinePusher, i: " + i); // put the replication offline PutReplicationOffline(pusher); // add a document string docFieldName = "testOnlineOfflinePusher" + i; string docFieldVal = "foo" + i; IDictionary<string, object> properties = new Dictionary<string, object>(); properties.Put(docFieldName, docFieldVal); CreateDocumentWithProperties(database, properties); // add a response listener to wait for a bulk_docs request from the pusher CountDownLatch gotBulkDocsRequest = new CountDownLatch(1); CustomizableMockHttpClient.ResponseListener bulkDocsListener = new _ResponseListener_1145 (gotBulkDocsRequest); mockHttpClient.AddResponseListener(bulkDocsListener); // put the replication online, which should trigger it to send outgoing bulk_docs request PutReplicationOnline(pusher); // wait until we get a bulk docs request Log.D(Database.Tag, "waiting for bulk docs request"); bool succeeded = gotBulkDocsRequest.Await(120, TimeUnit.Seconds); NUnit.Framework.Assert.IsTrue(succeeded); Log.D(Database.Tag, "got bulk docs request, verifying captured requests"); mockHttpClient.RemoveResponseListener(bulkDocsListener); // workaround bug https://github.com/couchbase/couchbase-lite-android/issues/219 Sharpen.Thread.Sleep(2000); // make sure that doc was pushed out in a bulk docs request bool foundExpectedDoc = false; IList<HttpWebRequest> capturedRequests = mockHttpClient.GetCapturedRequests(); foreach (HttpWebRequest capturedRequest in capturedRequests) { Log.D(Database.Tag, "captured request: " + capturedRequest); if (capturedRequest is HttpPost) { HttpPost capturedPostRequest = (HttpPost)capturedRequest; Log.D(Database.Tag, "capturedPostRequest: " + capturedPostRequest.GetURI().GetPath ()); if (capturedPostRequest.GetURI().GetPath().EndsWith("_bulk_docs")) { ArrayList docs = CustomizableMockHttpClient.ExtractDocsFromBulkDocsPost(capturedRequest ); NUnit.Framework.Assert.AreEqual(1, docs.Count); IDictionary<string, object> doc = (IDictionary)docs[0]; Log.D(Database.Tag, "doc from captured request: " + doc); Log.D(Database.Tag, "docFieldName: " + docFieldName); Log.D(Database.Tag, "expected docFieldVal: " + docFieldVal); Log.D(Database.Tag, "actual doc.get(docFieldName): " + doc.Get(docFieldName)); NUnit.Framework.Assert.AreEqual(docFieldVal, doc.Get(docFieldName)); foundExpectedDoc = true; } } } NUnit.Framework.Assert.IsTrue(foundExpectedDoc); mockHttpClient.ClearCapturedRequests(); } }