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