public void TestForceInsertEmptyHistory() { var rev = new RevisionInternal("FakeDocId", "1-tango", false, database); var revProperties = new Dictionary <string, object>(); revProperties.Put("_id", rev.GetDocId()); revProperties.Put("_rev", rev.GetRevId()); revProperties["message"] = "hi"; rev.SetProperties(revProperties); IList <string> revHistory = null; database.ForceInsert(rev, revHistory, null); }
private DocumentChange ChangeWithNewRevision(RevisionInternal inRev, bool isWinningRev, C4Document *doc, Uri source) { var winningRevId = default(string); if (isWinningRev) { winningRevId = inRev.GetRevId(); } else { winningRevId = (string)doc->revID; } return(new DocumentChange(inRev, winningRevId, doc->IsConflicted, source)); }
/// <exception cref="System.Exception"></exception> public virtual void TestCorrectWinningRevisionLongerBranch() { // Create a conflict on purpose Document doc = database.CreateDocument(); SavedRevision rev1 = doc.CreateRevision().Save(); SavedRevision rev2a = CreateRevisionWithRandomProps(rev1, false); SavedRevision rev2b = CreateRevisionWithRandomProps(rev1, true); SavedRevision rev3b = CreateRevisionWithRandomProps(rev2b, true); // rev3b should be picked as the winner since it has a longer branch SavedRevision expectedWinner = rev3b; RevisionInternal revFound = database.GetDocumentWithIDAndRev(doc.GetId(), null, EnumSet .NoneOf <Database.TDContentOptions>()); NUnit.Framework.Assert.AreEqual(expectedWinner.GetId(), revFound.GetRevId()); }
internal SavedRevision GetRevisionFromRev(RevisionInternal internalRevision) { if (internalRevision == null) { return(null); } if (currentRevision != null && internalRevision.GetRevId().Equals(CurrentRevision.Id)) { return(currentRevision); } else { return(new SavedRevision(this, internalRevision)); } }
public IDictionary <string, object> Invoke(RevisionInternal source) { AtomicBoolean hasAttachment = new AtomicBoolean(false); IList <string> attsSince = database.GetPossibleAncestorRevisionIDs(source, Puller. MaxNumberOfAttsSince, hasAttachment); if (!hasAttachment.Get() || attsSince.Count == 0) { attsSince = null; } IDictionary <string, object> mapped = new Dictionary <string, object>(); mapped.Put("id", source.GetDocId()); mapped.Put("rev", source.GetRevId()); mapped.Put("atts_since", attsSince); return(mapped); }
internal void RevisionAdded(DocumentChange documentChange) { RevisionInternal rev = documentChange.GetWinningRevision(); if (rev == null) { return; } // current revision didn't change if (currentRevision != null && !rev.GetRevId().Equals(currentRevision.GetId())) { currentRevision = new SavedRevision(this, rev); } foreach (Document.ChangeListener listener in changeListeners) { listener.Changed(new Document.ChangeEvent(this, documentChange)); } }
private static void VerifyHistory(Database db, RevisionInternal rev, IList <string > history) { RevisionInternal gotRev = db.GetDocumentWithIDAndRev(rev.GetDocId(), null, EnumSet .NoneOf <TDContentOptions>()); NUnit.Framework.Assert.AreEqual(rev, gotRev); NUnit.Framework.Assert.AreEqual(rev.Properties, gotRev.Properties); IList <RevisionInternal> revHistory = db.GetRevisionHistory(gotRev); NUnit.Framework.Assert.AreEqual(history.Count, revHistory.Count); for (int i = 0; i < history.Count; i++) { RevisionInternal hrev = revHistory[i]; NUnit.Framework.Assert.AreEqual(rev.GetDocId(), hrev.GetDocId()); NUnit.Framework.Assert.AreEqual(history[i], hrev.GetRevId()); NUnit.Framework.Assert.IsFalse(rev.IsDeleted()); } }
public RevisionInternal GetParentRevision(RevisionInternal rev) { var retVal = default(RevisionInternal); WithC4Document(rev.GetDocId(), rev.GetRevId(), false, false, doc => { if (!Native.c4doc_selectParentRevision(doc)) { return; } ForestDBBridge.Check(err => Native.c4doc_loadRevisionBody(doc, err)); retVal = new RevisionInternal((string)doc->docID, (string)doc->selectedRev.revID, doc->selectedRev.IsDeleted); retVal.SetSequence((long)doc->selectedRev.sequence); retVal.SetBody(new Body(doc->selectedRev.body)); }); return(retVal); }
/// <summary>https://github.com/couchbase/couchbase-lite-java-core/issues/135</summary> /// <exception cref="System.Exception"></exception> public virtual void TestCorrectWinningRevisionHighRevisionNumber() { // Create a conflict on purpose Document doc = database.CreateDocument(); SavedRevision rev1 = doc.CreateRevision().Save(); SavedRevision rev2a = CreateRevisionWithRandomProps(rev1, false); SavedRevision rev2b = CreateRevisionWithRandomProps(rev1, true); SavedRevision rev3b = CreateRevisionWithRandomProps(rev2b, true); SavedRevision rev4b = CreateRevisionWithRandomProps(rev3b, true); SavedRevision rev5b = CreateRevisionWithRandomProps(rev4b, true); SavedRevision rev6b = CreateRevisionWithRandomProps(rev5b, true); SavedRevision rev7b = CreateRevisionWithRandomProps(rev6b, true); SavedRevision rev8b = CreateRevisionWithRandomProps(rev7b, true); SavedRevision rev9b = CreateRevisionWithRandomProps(rev8b, true); SavedRevision rev10b = CreateRevisionWithRandomProps(rev9b, true); RevisionInternal revFound = database.GetDocumentWithIDAndRev(doc.GetId(), null, EnumSet .NoneOf <Database.TDContentOptions>()); NUnit.Framework.Assert.AreEqual(rev10b.GetId(), revFound.GetRevId()); }
private void VerifyHistory(Database db, RevisionInternal rev, IList <string> history) { var gotRev = db.GetDocumentWithIDAndRev(rev.GetDocId(), null, DocumentContentOptions.None); Assert.AreEqual(rev, gotRev); AssertPropertiesAreEqual(rev.GetProperties(), gotRev.GetProperties()); var revHistory = db.GetRevisionHistory(gotRev); Assert.AreEqual(history.Count, revHistory.Count); for (int i = 0; i < history.Count; i++) { RevisionInternal hrev = revHistory[i]; Assert.AreEqual(rev.GetDocId(), hrev.GetDocId()); Assert.AreEqual(history[i], hrev.GetRevId()); Assert.IsFalse(rev.IsDeleted()); } }
public IList <RevisionInternal> GetRevisionHistory(RevisionInternal rev, ICollection <string> ancestorRevIds) { var history = new List <RevisionInternal>(); WithC4Document(rev.GetDocId(), rev.GetRevId(), false, false, doc => { var enumerator = new CBForestHistoryEnumerator(doc, false); foreach (var next in enumerator) { if (ancestorRevIds != null && ancestorRevIds.Contains((string)next.SelectedRev.revID)) { break; } var newRev = new RevisionInternal(next.GetDocument(), false); newRev.SetMissing(!Native.c4doc_hasRevisionBody(next.GetDocument())); history.Add(newRev); } }); return(history); }
public void PullRemoteRevision(RevisionInternal rev) { Log.D(Database.Tag, this + "|" + Sharpen.Thread.CurrentThread().ToString() + ": pullRemoteRevision with rev: " + rev); Log.D(Database.Tag, this + "|" + Sharpen.Thread.CurrentThread() + ": pullRemoteRevision() calling asyncTaskStarted()" ); AsyncTaskStarted(); ++httpConnectionCount; // Construct a query. We want the revision history, and the bodies of attachments that have // been added since the latest revisions we have locally. // See: http://wiki.apache.org/couchdb/HTTP_Document_API#Getting_Attachments_With_a_Document StringBuilder path = new StringBuilder("/" + URLEncoder.Encode(rev.GetDocId()) + "?rev=" + URLEncoder.Encode(rev.GetRevId()) + "&revs=true&attachments=true"); IList <string> knownRevs = KnownCurrentRevIDs(rev); if (knownRevs == null) { //this means something is wrong, possibly the replicator has shut down Log.D(Database.Tag, this + "|" + Sharpen.Thread.CurrentThread() + ": pullRemoteRevision() calling asyncTaskFinished()" ); AsyncTaskFinished(1); --httpConnectionCount; return; } if (knownRevs.Count > 0) { path.Append("&atts_since="); path.Append(JoinQuotedEscaped(knownRevs)); } //create a final version of this variable for the log statement inside //FIXME find a way to avoid this string pathInside = path.ToString(); SendAsyncMultipartDownloaderRequest("GET", pathInside, null, db, new _RemoteRequestCompletionBlock_336 (this, rev, pathInside)); }
/// <summary> /// Creates a dictionary of metadata for one specific revision /// </summary> /// <returns>The metadata dictionary</returns> /// <param name="rev">The revision to examine</param> /// <param name="responseState">The current response state</param> public static IDictionary <string, object> ChangesDictForRev(RevisionInternal rev, DBMonitorCouchbaseResponseState responseState) { if (responseState.ChangesIncludeDocs) { var status = new Status(); var rev2 = DocumentMethods.ApplyOptions(responseState.ContentOptions, rev, responseState.Context, responseState.Db, status); if (rev2 != null) { rev2.SetSequence(rev.GetSequence()); rev = rev2; } } return(new NonNullDictionary <string, object> { { "seq", rev.GetSequence() }, { "id", rev.GetDocId() }, { "changes", new List <object> { new Dictionary <string, object> { { "rev", rev.GetRevId() } } } }, { "deleted", rev.IsDeleted() ? (object)true : null }, { "doc", responseState.ChangesIncludeDocs ? rev.GetProperties() : null } }); }
/// <exception cref="System.Exception"></exception> public virtual void TestPusher() { CountDownLatch replicationDoneSignal = new CountDownLatch(1); Uri remote = GetReplicationURL(); string docIdTimestamp = System.Convert.ToString(Runtime.CurrentTimeMillis()); // Create some documents: IDictionary <string, object> documentProperties = new Dictionary <string, object>(); string doc1Id = string.Format("doc1-%s", docIdTimestamp); documentProperties.Put("_id", doc1Id); documentProperties.Put("foo", 1); documentProperties.Put("bar", false); Body body = new Body(documentProperties); RevisionInternal rev1 = new RevisionInternal(body, database); Status status = new Status(); rev1 = database.PutRevision(rev1, null, false, status); NUnit.Framework.Assert.AreEqual(Status.Created, status.GetCode()); documentProperties.Put("_rev", rev1.GetRevId()); documentProperties.Put("UPDATED", true); RevisionInternal rev2 = database.PutRevision(new RevisionInternal(documentProperties , database), rev1.GetRevId(), false, status); NUnit.Framework.Assert.AreEqual(Status.Created, status.GetCode()); documentProperties = new Dictionary <string, object>(); string doc2Id = string.Format("doc2-%s", docIdTimestamp); documentProperties.Put("_id", doc2Id); documentProperties.Put("baz", 666); documentProperties.Put("fnord", true); database.PutRevision(new RevisionInternal(documentProperties, database), null, false , status); NUnit.Framework.Assert.AreEqual(Status.Created, status.GetCode()); bool continuous = false; Replication repl = database.CreatePushReplication(remote); repl.SetContinuous(continuous); repl.SetCreateTarget(true); // Check the replication's properties: NUnit.Framework.Assert.AreEqual(database, repl.GetLocalDatabase()); NUnit.Framework.Assert.AreEqual(remote, repl.GetRemoteUrl()); NUnit.Framework.Assert.IsFalse(repl.IsPull()); NUnit.Framework.Assert.IsFalse(repl.IsContinuous()); NUnit.Framework.Assert.IsTrue(repl.ShouldCreateTarget()); NUnit.Framework.Assert.IsNull(repl.GetFilter()); NUnit.Framework.Assert.IsNull(repl.GetFilterParams()); // TODO: CAssertNil(r1.doc_ids); // TODO: CAssertNil(r1.headers); // Check that the replication hasn't started running: NUnit.Framework.Assert.IsFalse(repl.IsRunning()); NUnit.Framework.Assert.AreEqual(Replication.ReplicationStatus.ReplicationStopped, repl.GetStatus()); NUnit.Framework.Assert.AreEqual(0, repl.GetCompletedChangesCount()); NUnit.Framework.Assert.AreEqual(0, repl.GetChangesCount()); NUnit.Framework.Assert.IsNull(repl.GetLastError()); RunReplication(repl); // make sure doc1 is there // TODO: make sure doc2 is there (refactoring needed) Uri replicationUrlTrailing = new Uri(string.Format("%s/", remote.ToExternalForm() )); Uri pathToDoc = new Uri(replicationUrlTrailing, doc1Id); Log.D(Tag, "Send http request to " + pathToDoc); CountDownLatch httpRequestDoneSignal = new CountDownLatch(1); BackgroundTask getDocTask = new _BackgroundTask_122(pathToDoc, doc1Id, httpRequestDoneSignal ); //Closes the connection. getDocTask.Execute(); Log.D(Tag, "Waiting for http request to finish"); try { httpRequestDoneSignal.Await(300, TimeUnit.Seconds); Log.D(Tag, "http request finished"); } catch (Exception e) { Sharpen.Runtime.PrintStackTrace(e); } Log.D(Tag, "testPusher() finished"); }
public static ICouchbaseResponseState RevsDiff(ICouchbaseListenerContext context) { // Collect all of the input doc/revision IDs as CBL_Revisions: var revs = new RevisionList(); var body = context.BodyAs <Dictionary <string, object> >(); if (body == null) { return(context.CreateResponse(StatusCode.BadJson).AsDefaultState()); } foreach (var docPair in body) { var revIDs = docPair.Value.AsList <string>(); if (revIDs == null) { return(context.CreateResponse(StatusCode.BadParam).AsDefaultState()); } foreach (var revID in revIDs) { var rev = new RevisionInternal(docPair.Key, revID, false); revs.Add(rev); } } return(PerformLogicWithDatabase(context, true, db => { var response = context.CreateResponse(); // Look them up, removing the existing ones from revs: db.Storage.FindMissingRevisions(revs); // Return the missing revs in a somewhat different format: IDictionary <string, object> diffs = new Dictionary <string, object>(); foreach (var rev in revs) { var docId = rev.GetDocId(); IList <string> missingRevs = null; if (!diffs.ContainsKey(docId)) { missingRevs = new List <string>(); diffs[docId] = new Dictionary <string, IList <string> > { { "missing", missingRevs } }; } else { missingRevs = ((Dictionary <string, IList <string> >)diffs[docId])["missing"]; } missingRevs.Add(rev.GetRevId()); } // Add the possible ancestors for each missing revision: foreach (var docPair in diffs) { IDictionary <string, IList <string> > docInfo = (IDictionary <string, IList <string> >)docPair.Value; int maxGen = 0; string maxRevID = null; foreach (var revId in docInfo["missing"]) { var parsed = RevisionInternal.ParseRevId(revId); if (parsed.Item1 > maxGen) { maxGen = parsed.Item1; maxRevID = revId; } } var rev = new RevisionInternal(docPair.Key, maxRevID, false); var ancestors = db.Storage.GetPossibleAncestors(rev, 0, false); var ancestorList = ancestors == null ? null : ancestors.ToList(); if (ancestorList != null && ancestorList.Count > 0) { docInfo["possible_ancestors"] = ancestorList; } } response.JsonBody = new Body(diffs); return response; }).AsDefaultState()); }
/// <summary>Fetches the contents of a revision from the remote db, including its parent revision ID. /// </summary> /// <remarks> /// Fetches the contents of a revision from the remote db, including its parent revision ID. /// The contents are stored into rev.properties. /// </remarks> internal void PullRemoteRevision(RevisionInternal rev) { Log.D(Tag, "PullRemoteRevision with rev: {0}", rev); Log.D(Tag, "PullRemoteRevision() calling AsyncTaskStarted()"); AsyncTaskStarted(); httpConnectionCount++; // Construct a query. We want the revision history, and the bodies of attachments that have // been added since the latest revisions we have locally. // See: http://wiki.apache.org/couchdb/HTTP_Document_API#Getting_Attachments_With_a_Document var path = new StringBuilder("/" + Uri.EscapeUriString(rev.GetDocId()) + "?rev=" + Uri.EscapeUriString(rev.GetRevId()) + "&revs=true&attachments=true"); var knownRevs = KnownCurrentRevIDs(rev); if (knownRevs == null) { //this means something is wrong, possibly the replicator has shut down Log.D(Tag, "PullRemoteRevision() calling AsyncTaskFinished()"); AsyncTaskFinished(1); httpConnectionCount--; return; } if (knownRevs.Count > 0) { path.Append("&atts_since="); path.Append(JoinQuotedEscaped(knownRevs)); } //create a final version of this variable for the log statement inside //FIXME find a way to avoid this var pathInside = path.ToString(); SendAsyncMultipartDownloaderRequest(HttpMethod.Get, pathInside, null, LocalDatabase, (result, e) => { try { // OK, now we've got the response revision: Log.D(Tag, "PullRemoteRevision got response for rev: " + rev); if (e != null) { Log.E(Tag, "Error pulling remote revision", e); SetLastError(e); RevisionFailed(); Log.D(Tag, "PullRemoteRevision updating completedChangesCount from " + CompletedChangesCount + " -> " + (CompletedChangesCount + 1) + " due to error pulling remote revision"); SafeIncrementCompletedChangesCount(); } else { var properties = result.AsDictionary <string, object>(); var gotRev = new PulledRevision(properties); gotRev.SetSequence(rev.GetSequence()); AsyncTaskStarted(); Log.D(Tag, "PullRemoteRevision add rev: " + gotRev + " to batcher"); if (downloadsToInsert != null) { downloadsToInsert.QueueObject(gotRev); } else { Log.E(Tag, "downloadsToInsert is null"); } } } finally { Log.D(Tag, "PullRemoteRevision.onCompletion() calling AsyncTaskFinished()"); AsyncTaskFinished(1); } // Note that we've finished this task; then start another one if there // are still revisions waiting to be pulled: --httpConnectionCount; PullRemoteRevisions(); }); }
public void TestLocalDocs() { //create a document var documentProperties = new Dictionary <string, object>(); documentProperties["_id"] = "_local/doc1"; documentProperties["foo"] = 1; documentProperties["bar"] = false; var body = new Body(documentProperties); var rev1 = new RevisionInternal(body); rev1 = database.PutLocalRevision(rev1, null); Log.V(Tag, "Created " + rev1); Assert.AreEqual("_local/doc1", rev1.GetDocId()); Assert.IsTrue(rev1.GetRevId().StartsWith("1-")); //read it back var readRev = database.GetLocalDocument(rev1.GetDocId(), null); Assert.IsNotNull(readRev); var readRevProps = readRev.GetProperties(); Assert.AreEqual(rev1.GetDocId(), readRevProps.Get("_id")); Assert.AreEqual(rev1.GetRevId(), readRevProps.Get("_rev")); AssertPropertiesAreEqual(UserProperties(readRevProps), UserProperties(body.GetProperties())); //now update it documentProperties = (Dictionary <string, object>)readRev.GetProperties(); documentProperties["status"] = "updated!"; body = new Body(documentProperties); var rev2 = new RevisionInternal(body); var rev2input = rev2; rev2 = database.PutLocalRevision(rev2, rev1.GetRevId()); Log.V(Tag, "Updated " + rev1); Assert.AreEqual(rev1.GetDocId(), rev2.GetDocId()); Assert.IsTrue(rev2.GetRevId().StartsWith("2-")); //read it back readRev = database.GetLocalDocument(rev2.GetDocId(), null); Assert.IsNotNull(readRev); AssertPropertiesAreEqual(UserProperties(readRev.GetProperties()), UserProperties(body.GetProperties())); // Try to update the first rev, which should fail: var gotException = false; try { database.PutLocalRevision(rev2input, rev1.GetRevId()); } catch (CouchbaseLiteException e) { Assert.AreEqual(StatusCode.Conflict, e.GetCBLStatus().GetCode()); gotException = true; } Assert.IsTrue(gotException); // Delete it: var revD = new RevisionInternal(rev2.GetDocId(), null, true); gotException = false; try { var revResult = database.PutLocalRevision(revD, null); Assert.IsNull(revResult); } catch (CouchbaseLiteException e) { Assert.AreEqual(StatusCode.Conflict, e.GetCBLStatus().GetCode()); gotException = true; } Assert.IsTrue(gotException); revD = database.PutLocalRevision(revD, rev2.GetRevId()); // Delete nonexistent doc: gotException = false; var revFake = new RevisionInternal("_local/fake", null, true); try { database.PutLocalRevision(revFake, null); } catch (CouchbaseLiteException e) { Assert.AreEqual(StatusCode.NotFound, e.GetCBLStatus().GetCode()); gotException = true; } Assert.IsTrue(gotException); // Read it back (should fail): readRev = database.GetLocalDocument(revD.GetDocId(), null); Assert.IsNull(readRev); }
/// <summary>Creates and saves a new revision with the given properties.</summary> /// <remarks> /// Creates and saves a new <see cref="Couchbase.Lite.Revision"/> with the specified properties. To succeed the specified properties must include a '_rev' property whose value maches the current %Revision's% id. /// This will fail with a 412 error if the receiver is not the current revision of the document. /// </remarks> /// <returns> /// The new <see cref="Couchbase.Lite.SavedRevision"/>. /// </returns> /// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public SavedRevision CreateRevision(IDictionary <String, Object> properties) { return(Document.PutProperties(properties, RevisionInternal.GetRevId(), allowConflict: false)); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestValidations() { Validator validator = new _Validator_19(this); database.SetValidation("hoopy", validator); // POST a valid new document: IDictionary <string, object> props = new Dictionary <string, object>(); props.Put("name", "Zaphod Beeblebrox"); props.Put("towel", "velvet"); RevisionInternal rev = new RevisionInternal(props, database); Status status = new Status(); validationCalled = false; rev = database.PutRevision(rev, null, false, status); NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.AreEqual(Status.Created, status.GetCode()); // PUT a valid update: props.Put("head_count", 3); rev.SetProperties(props); validationCalled = false; rev = database.PutRevision(rev, rev.GetRevId(), false, status); NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.AreEqual(Status.Created, status.GetCode()); // PUT an invalid update: Sharpen.Collections.Remove(props, "towel"); rev.SetProperties(props); validationCalled = false; bool gotExpectedError = false; try { rev = database.PutRevision(rev, rev.GetRevId(), false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == Status.Forbidden); } NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.IsTrue(gotExpectedError); // POST an invalid new document: props = new Dictionary <string, object>(); props.Put("name", "Vogon"); props.Put("poetry", true); rev = new RevisionInternal(props, database); validationCalled = false; gotExpectedError = false; try { rev = database.PutRevision(rev, null, false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == Status.Forbidden); } NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.IsTrue(gotExpectedError); // PUT a valid new document with an ID: props = new Dictionary <string, object>(); props.Put("_id", "ford"); props.Put("name", "Ford Prefect"); props.Put("towel", "terrycloth"); rev = new RevisionInternal(props, database); validationCalled = false; rev = database.PutRevision(rev, null, false, status); NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.AreEqual("ford", rev.GetDocId()); // DELETE a document: rev = new RevisionInternal(rev.GetDocId(), rev.GetRevId(), true, database); NUnit.Framework.Assert.IsTrue(rev.IsDeleted()); validationCalled = false; rev = database.PutRevision(rev, rev.GetRevId(), false, status); NUnit.Framework.Assert.IsTrue(validationCalled); // PUT an invalid new document: props = new Dictionary <string, object>(); props.Put("_id", "petunias"); props.Put("name", "Pot of Petunias"); rev = new RevisionInternal(props, database); validationCalled = false; gotExpectedError = false; try { rev = database.PutRevision(rev, null, false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == Status.Forbidden); } NUnit.Framework.Assert.IsTrue(validationCalled); NUnit.Framework.Assert.IsTrue(gotExpectedError); }
public virtual void TestPusher() { var replicationDoneSignal = new CountDownLatch(1); var remote = GetReplicationURL(); var docIdTimestamp = Convert.ToString(Runtime.CurrentTimeMillis()); // Create some documents: var documentProperties = new Dictionary <string, object>(); var doc1Id = string.Format("doc1-{0}", docIdTimestamp); documentProperties["_id"] = doc1Id; documentProperties["foo"] = 1; documentProperties["bar"] = false; var body = new Body(documentProperties); var rev1 = new RevisionInternal(body, database); var status = new Status(); rev1 = database.PutRevision(rev1, null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties.Put("_rev", rev1.GetRevId()); documentProperties["UPDATED"] = true; var rev2 = database.PutRevision(new RevisionInternal(documentProperties, database), rev1.GetRevId(), false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties = new Dictionary <string, object>(); var doc2Id = string.Format("doc2-{0}", docIdTimestamp); documentProperties["_id"] = doc2Id; documentProperties["baz"] = 666; documentProperties["fnord"] = true; database.PutRevision(new RevisionInternal(documentProperties, database), null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); var continuous = false; var repl = database.CreatePushReplication(remote); repl.Continuous = continuous; //repl.CreateTarget = false; // Check the replication's properties: Assert.AreEqual(database, repl.LocalDatabase); Assert.AreEqual(remote, repl.RemoteUrl); Assert.IsFalse(repl.IsPull); Assert.IsFalse(repl.Continuous); //Assert.IsTrue(repl.CreateTarget); Assert.IsNull(repl.Filter); Assert.IsNull(repl.FilterParams); // TODO: CAssertNil(r1.doc_ids); // TODO: CAssertNil(r1.headers); // Check that the replication hasn't started running: Assert.IsFalse(repl.IsRunning); Assert.AreEqual((int)repl.Status, (int)ReplicationStatus.Stopped); Assert.AreEqual(0, repl.CompletedChangesCount); Assert.AreEqual(0, repl.ChangesCount); Assert.IsNull(repl.LastError); RunReplication(repl); // make sure doc1 is there // TODO: make sure doc2 is there (refactoring needed) var replicationUrlTrailing = new Uri(string.Format("{0}/", remote)); var pathToDoc = new Uri(replicationUrlTrailing, doc1Id); Log.D(Tag, "Send http request to " + pathToDoc); var httpRequestDoneSignal = new CountDownLatch(1); var getDocTask = Task.Factory.StartNew(() => { var httpclient = new HttpClient(); HttpResponseMessage response; string responseString = null; try { var responseTask = httpclient.GetAsync(pathToDoc.ToString()); responseTask.Wait(TimeSpan.FromSeconds(10)); response = responseTask.Result; var statusLine = response.StatusCode; NUnit.Framework.Assert.IsTrue(statusLine == HttpStatusCode.OK); if (statusLine == HttpStatusCode.OK) { var responseStringTask = response.Content.ReadAsStringAsync(); responseStringTask.Wait(TimeSpan.FromSeconds(10)); responseString = responseStringTask.Result; NUnit.Framework.Assert.IsTrue(responseString.Contains(doc1Id)); Log.D(ReplicationTest.Tag, "result: " + responseString); } else { var statusReason = response.ReasonPhrase; response.Dispose(); throw new IOException(statusReason); } } catch (ProtocolViolationException e) { NUnit.Framework.Assert.IsNull(e, "Got ClientProtocolException: " + e.Message); } catch (IOException e) { NUnit.Framework.Assert.IsNull(e, "Got IOException: " + e.Message); } httpRequestDoneSignal.CountDown(); }); //Closes the connection. Log.D(Tag, "Waiting for http request to finish"); try { var result = httpRequestDoneSignal.Await(TimeSpan.FromSeconds(10)); Assert.IsTrue(result, "Could not retrieve the new doc from the sync gateway."); Log.D(Tag, "http request finished"); } catch (Exception e) { Sharpen.Runtime.PrintStackTrace(e); } Log.D(Tag, "testPusher() finished"); }
/// <summary>Fetches the contents of a revision from the remote db, including its parent revision ID. /// </summary> /// <remarks> /// Fetches the contents of a revision from the remote db, including its parent revision ID. /// The contents are stored into rev.properties. /// </remarks> internal void PullRemoteRevision(RevisionInternal rev) { Log.D(Tag, this + "|" + Thread.CurrentThread() + ": pullRemoteRevision with rev: " + rev); Log.D(Tag, this + "|" + Thread.CurrentThread() + ": pullRemoteRevision() calling asyncTaskStarted()"); AsyncTaskStarted(); httpConnectionCount++; // Construct a query. We want the revision history, and the bodies of attachments that have // been added since the latest revisions we have locally. // See: http://wiki.apache.org/couchdb/HTTP_Document_API#Getting_Attachments_With_a_Document var path = new StringBuilder("/" + HttpUtility.UrlEncode(rev.GetDocId()) + "?rev=" + HttpUtility.UrlEncode(rev.GetRevId()) + "&revs=true&attachments=true"); var knownRevs = KnownCurrentRevIDs(rev); if (knownRevs == null) { //this means something is wrong, possibly the replicator has shut down Log.D(Tag, this + "|" + Thread.CurrentThread() + ": pullRemoteRevision() calling asyncTaskFinished()"); AsyncTaskFinished(1); httpConnectionCount--; return; } if (knownRevs.Count > 0) { path.Append("&atts_since="); path.Append(JoinQuotedEscaped(knownRevs)); } //create a final version of this variable for the log statement inside //FIXME find a way to avoid this var pathInside = path.ToString(); SendAsyncMultipartDownloaderRequest(HttpMethod.Get, pathInside, null, LocalDatabase, (result, e) => { try { // OK, now we've got the response revision: Log.D(Tag, this + ": pullRemoteRevision got response for rev: " + rev); if (result != null) { var properties = ((JObject)result).ToObject <IDictionary <string, object> >(); var history = Database.ParseCouchDBRevisionHistory(properties); if (history != null) { rev.SetProperties(properties); // Add to batcher ... eventually it will be fed to -insertRevisions:. var toInsert = new AList <object> (); toInsert.AddItem(rev); toInsert.AddItem(history); Log.D(Tag, this + ": pullRemoteRevision add rev: " + rev + " to batcher"); downloadsToInsert.QueueObject(toInsert); Log.D(Tag, this + "|" + Thread.CurrentThread() + ": pullRemoteRevision.onCompletion() calling asyncTaskStarted()"); AsyncTaskStarted(); } else { Log.W(Tag, this + ": Missing revision history in response from " + pathInside); CompletedChangesCount += 1; } } else { if (e != null) { Log.E(Tag, "Error pulling remote revision", e); LastError = e; } CompletedChangesCount += 1; } } finally { Log.D(Tag, this + "|" + Thread.CurrentThread() + ": pullRemoteRevision.onCompletion() calling asyncTaskFinished()"); AsyncTaskFinished(1); } // Note that we've finished this task; then start another one if there // are still revisions waiting to be pulled: --httpConnectionCount; PullRemoteRevisions(); }); }
public void TestAttachments() { const string testAttachmentName = "test_attachment"; var attachments = database.Attachments; Assert.AreEqual(0, attachments.Count()); Assert.AreEqual(0, attachments.AllKeys().Count()); var attach1 = Encoding.UTF8.GetBytes("This is the body of attach1"); var props = new Dictionary <string, object> { { "foo", 1 }, { "bar", false }, { "_attachments", CreateAttachmentsDict(attach1, testAttachmentName, "text/plain", false) } }; Status status = new Status(); RevisionInternal rev1 = database.PutRevision(new RevisionInternal(props), null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); var att = database.GetAttachmentForRevision(rev1, testAttachmentName, status); Assert.IsNotNull(att, "Couldn't get attachment: Status {0}", status.GetCode()); Assert.AreEqual(attach1, att.Content); Assert.AreEqual("text/plain", att.ContentType); Assert.AreEqual(AttachmentEncoding.None, att.Encoding); var itemDict = new Dictionary <string, object> { { "content_type", "text/plain" }, { "digest", "sha1-gOHUOBmIMoDCrMuGyaLWzf1hQTE=" }, { "length", 27 }, { "stub", true }, { "revpos", 1 } }; var attachmentDict = new Dictionary <string, object> { { testAttachmentName, itemDict } }; var gotRev1 = database.GetDocumentWithIDAndRev(rev1.GetDocId(), rev1.GetRevId(), DocumentContentOptions.None); AssertDictionariesAreEqual(attachmentDict, gotRev1.GetAttachments()); itemDict.Remove("stub"); itemDict["data"] = Convert.ToBase64String(attach1); gotRev1 = database.GetDocumentWithIDAndRev(rev1.GetDocId(), rev1.GetRevId(), DocumentContentOptions.IncludeAttachments); var expandedRev = gotRev1.CopyWithDocID(rev1.GetDocId(), rev1.GetRevId()); Assert.IsTrue(database.ExpandAttachments(expandedRev, 0, false, true, status)); AssertDictionariesAreEqual(attachmentDict, expandedRev.GetAttachments()); // Add a second revision that doesn't update the attachment: props = new Dictionary <string, object> { { "_id", rev1.GetDocId() }, { "foo", 2 }, { "bazz", false }, { "_attachments", CreateAttachmentsStub(testAttachmentName) } }; var rev2 = database.PutRevision(new RevisionInternal(props), rev1.GetRevId(), status); Assert.AreEqual(StatusCode.Created, status.GetCode()); // Add a third revision of the same document: var attach2 = Encoding.UTF8.GetBytes("<html>And this is attach2</html>"); props = new Dictionary <string, object> { { "_id", rev2.GetDocId() }, { "foo", 2 }, { "bazz", false }, { "_attachments", CreateAttachmentsDict(attach2, testAttachmentName, "text/html", false) } }; var rev3 = database.PutRevision(new RevisionInternal(props), rev2.GetRevId(), status); Assert.AreEqual(StatusCode.Created, status.GetCode()); // Check the second revision's attachment att = database.GetAttachmentForRevision(rev2, testAttachmentName, status); Assert.IsNotNull(att, "Couldn't get attachment: Status {0}", status.GetCode()); Assert.AreEqual(attach1, att.Content); Assert.AreEqual("text/plain", att.ContentType); Assert.AreEqual(AttachmentEncoding.None, att.Encoding); expandedRev = rev2.CopyWithDocID(rev2.GetDocId(), rev2.GetRevId()); Assert.IsTrue(database.ExpandAttachments(expandedRev, 2, false, true, status)); AssertDictionariesAreEqual(new Dictionary <string, object> { { testAttachmentName, new Dictionary <string, object> { { "stub", true }, { "revpos", 1 } } } }, expandedRev.GetAttachments()); // Check the 3rd revision's attachment: att = database.GetAttachmentForRevision(rev3, testAttachmentName, status); Assert.IsNotNull(att, "Couldn't get attachment: Status {0}", status.GetCode()); Assert.AreEqual(attach2, att.Content); Assert.AreEqual("text/html", att.ContentType); Assert.AreEqual(AttachmentEncoding.None, att.Encoding); expandedRev = rev3.CopyWithDocID(rev3.GetDocId(), rev3.GetRevId()); Assert.IsTrue(database.ExpandAttachments(expandedRev, 2, false, true, status)); attachmentDict = new Dictionary <string, object> { { testAttachmentName, new Dictionary <string, object> { { "content_type", "text/html" }, { "data", "PGh0bWw+QW5kIHRoaXMgaXMgYXR0YWNoMjwvaHRtbD4=" }, { "digest", "sha1-s14XRTXlwvzYfjo1t1u0rjB+ZUA=" }, { "length", 32 }, { "revpos", 3 } } } }; AssertDictionariesAreEqual(attachmentDict, expandedRev.GetAttachments()); // Examine the attachment store: Assert.AreEqual(2, attachments.Count()); Assert.AreEqual(new HashSet <BlobKey> { BlobStore.KeyForBlob(attach1), BlobStore.KeyForBlob(attach2) }, attachments.AllKeys()); database.Compact(); Assert.AreEqual(1, attachments.Count()); Assert.AreEqual(new HashSet <BlobKey> { BlobStore.KeyForBlob(attach2) }, attachments.AllKeys()); }
public virtual void TestPusherDeletedDoc() { Assert.Fail(); // TODO.ZJG: Needs debugging, overflows stack. CountDownLatch replicationDoneSignal = new CountDownLatch(1); Uri remote = GetReplicationURL(); string docIdTimestamp = System.Convert.ToString(Runtime.CurrentTimeMillis()); // Create some documentsConvert IDictionary <string, object> documentProperties = new Dictionary <string, object>(); string doc1Id = string.Format("doc1-{0}", docIdTimestamp); documentProperties["_id"] = doc1Id; documentProperties["foo"] = 1; documentProperties["bar"] = false; Body body = new Body(documentProperties); RevisionInternal rev1 = new RevisionInternal(body, database); Status status = new Status(); rev1 = database.PutRevision(rev1, null, false, status); NUnit.Framework.Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties["_rev"] = rev1.GetRevId(); documentProperties["UPDATED"] = true; documentProperties["_deleted"] = true; RevisionInternal rev2 = database.PutRevision(new RevisionInternal(documentProperties , database), rev1.GetRevId(), false, status); NUnit.Framework.Assert.IsTrue((int)status.GetCode() >= 200 && (int)status.GetCode() < 300); var repl = database.CreatePushReplication(remote); ((Pusher)repl).CreateTarget = true; RunReplication(repl); // make sure doc1 is deleted Uri replicationUrlTrailing = new Uri(string.Format("{0}/", remote.ToString() )); Uri pathToDoc = new Uri(replicationUrlTrailing, doc1Id); Log.D(Tag, "Send http request to " + pathToDoc); CountDownLatch httpRequestDoneSignal = new CountDownLatch(1); var getDocTask = Task.Factory.StartNew(() => { var httpclient = new HttpClient(); HttpResponseMessage response; string responseString = null; try { var responseTask = httpclient.GetAsync(pathToDoc.ToString()); responseTask.Wait(); response = responseTask.Result; var statusLine = response.StatusCode; Log.D(ReplicationTest.Tag, "statusLine " + statusLine); Assert.AreEqual(HttpStatusCode.NotFound, statusLine.GetStatusCode()); } catch (ProtocolViolationException e) { NUnit.Framework.Assert.IsNull(e, "Got ClientProtocolException: " + e.Message); } catch (IOException e) { NUnit.Framework.Assert.IsNull(e, "Got IOException: " + e.Message); } finally { httpRequestDoneSignal.CountDown(); } }); getDocTask.Start(); Log.D(Tag, "Waiting for http request to finish"); try { httpRequestDoneSignal.Await(TimeSpan.FromSeconds(10)); Log.D(Tag, "http request finished"); } catch (Exception e) { Sharpen.Runtime.PrintStackTrace(e); } Log.D(Tag, "testPusherDeletedDoc() finished"); }
public virtual void TestPutAttachment() { const string testAttachmentName = "test_attachment"; var attachments = database.Attachments; attachments.DeleteBlobs(); Assert.AreEqual(0, attachments.Count()); // Put a revision that includes an _attachments dict: var attach1 = Encoding.UTF8.GetBytes("This is the body of attach1"); var base64 = Convert.ToBase64String(attach1); var attachment = new Dictionary <string, object>(); attachment["content_type"] = "text/plain"; attachment["data"] = base64; IDictionary <string, object> attachmentDict = new Dictionary <string, object>(); attachmentDict[testAttachmentName] = attachment; var properties = new Dictionary <string, object>(); properties["foo"] = 1; properties["bar"] = false; properties["_attachments"] = attachmentDict; var rev1 = database.PutRevision(new RevisionInternal(properties), null, false); // Examine the attachment store: Assert.AreEqual(1, attachments.Count()); // Get the revision: var gotRev1 = database.GetDocumentWithIDAndRev(rev1.GetDocId(), rev1.GetRevId(), DocumentContentOptions.None); var gotAttachmentDict = gotRev1.GetPropertyForKey("_attachments").AsDictionary <string, object>(); var innerDict = new JObject(); innerDict["content_type"] = "text/plain"; innerDict["digest"] = "sha1-gOHUOBmIMoDCrMuGyaLWzf1hQTE="; innerDict["length"] = 27; innerDict["stub"] = true; innerDict["revpos"] = 1; var expectAttachmentDict = new Dictionary <string, object>(); expectAttachmentDict[testAttachmentName] = innerDict; Assert.AreEqual(expectAttachmentDict, gotAttachmentDict); // Update the attachment directly: var attachv2 = Encoding.UTF8.GetBytes("Replaced body of attach"); var writer = new BlobStoreWriter(database.Attachments); writer.AppendData(attachv2); writer.Finish(); var gotExpectedErrorCode = false; try { database.UpdateAttachment(testAttachmentName, writer, "application/foo", AttachmentEncoding.None, rev1.GetDocId(), null); } catch (CouchbaseLiteException e) { gotExpectedErrorCode = (e.GetCBLStatus().GetCode() == StatusCode.Conflict); } Assert.IsTrue(gotExpectedErrorCode); gotExpectedErrorCode = false; try { database.UpdateAttachment(testAttachmentName, new BlobStoreWriter(database.Attachments), "application/foo", AttachmentEncoding.None, rev1.GetDocId(), "1-bogus"); } catch (CouchbaseLiteException e) { gotExpectedErrorCode = (e.GetCBLStatus().GetCode() == StatusCode.Conflict); } Assert.IsTrue(gotExpectedErrorCode); gotExpectedErrorCode = false; RevisionInternal rev2 = null; try { rev2 = database.UpdateAttachment(testAttachmentName, writer, "application/foo", AttachmentEncoding.None, rev1.GetDocId(), rev1.GetRevId()); } catch (CouchbaseLiteException) { gotExpectedErrorCode = true; } Assert.IsFalse(gotExpectedErrorCode); Assert.AreEqual(rev1.GetDocId(), rev2.GetDocId()); Assert.AreEqual(2, rev2.GetGeneration()); // Get the updated revision: RevisionInternal gotRev2 = database.GetDocumentWithIDAndRev(rev2.GetDocId(), rev2 .GetRevId(), DocumentContentOptions.None); attachmentDict = gotRev2.GetProperties().Get("_attachments").AsDictionary <string, object>(); innerDict = new JObject(); innerDict["content_type"] = "application/foo"; innerDict["digest"] = "sha1-mbT3208HI3PZgbG4zYWbDW2HsPk="; innerDict["length"] = 23; innerDict["stub"] = true; innerDict["revpos"] = 2; expectAttachmentDict[testAttachmentName] = innerDict; Assert.AreEqual(expectAttachmentDict, attachmentDict); // Delete the attachment: gotExpectedErrorCode = false; try { database.UpdateAttachment("nosuchattach", null, "application/foo", AttachmentEncoding.None, rev2.GetDocId(), rev2.GetRevId()); } catch (CouchbaseLiteException e) { gotExpectedErrorCode = (e.GetCBLStatus().GetCode() == StatusCode.NotFound); } Assert.IsTrue(gotExpectedErrorCode); gotExpectedErrorCode = false; try { database.UpdateAttachment("nosuchattach", null, null, AttachmentEncoding.None, "nosuchdoc", "nosuchrev"); } catch (CouchbaseLiteException e) { gotExpectedErrorCode = (e.GetCBLStatus().GetCode() == StatusCode.NotFound); } Assert.IsTrue(gotExpectedErrorCode); RevisionInternal rev3 = database.UpdateAttachment(testAttachmentName, null, null, AttachmentEncoding.None, rev2.GetDocId(), rev2.GetRevId()); Assert.AreEqual(rev2.GetDocId(), rev3.GetDocId()); Assert.AreEqual(3, rev3.GetGeneration()); // Get the updated revision: RevisionInternal gotRev3 = database.GetDocumentWithIDAndRev(rev3.GetDocId(), rev3 .GetRevId(), DocumentContentOptions.None); attachmentDict = gotRev3.GetProperties().Get("_attachments").AsDictionary <string, object>(); Assert.IsNull(attachmentDict); database.Close(); }
public void TestPusher() { var remote = GetReplicationURL(); var docIdTimestamp = Convert.ToString(Runtime.CurrentTimeMillis()); // Create some documents: var documentProperties = new Dictionary <string, object>(); var doc1Id = string.Format("doc1-{0}", docIdTimestamp); documentProperties["_id"] = doc1Id; documentProperties["foo"] = 1; documentProperties["bar"] = false; var body = new Body(documentProperties); var rev1 = new RevisionInternal(body, database); var status = new Status(); rev1 = database.PutRevision(rev1, null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties.Put("_rev", rev1.GetRevId()); documentProperties["UPDATED"] = true; database.PutRevision(new RevisionInternal(documentProperties, database), rev1.GetRevId(), false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties = new Dictionary <string, object>(); var doc2Id = string.Format("doc2-{0}", docIdTimestamp); documentProperties["_id"] = doc2Id; documentProperties["baz"] = 666; documentProperties["fnord"] = true; database.PutRevision(new RevisionInternal(documentProperties, database), null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); var doc2 = database.GetDocument(doc2Id); var doc2UnsavedRev = doc2.CreateRevision(); var attachmentStream = GetAsset("attachment.png"); doc2UnsavedRev.SetAttachment("attachment.png", "image/png", attachmentStream); var doc2Rev = doc2UnsavedRev.Save(); Assert.IsNotNull(doc2Rev); const bool continuous = false; var repl = database.CreatePushReplication(remote); repl.Continuous = continuous; if (!IsSyncGateway(remote)) { repl.CreateTarget = true; } // Check the replication's properties: Assert.AreEqual(database, repl.LocalDatabase); Assert.AreEqual(remote, repl.RemoteUrl); Assert.IsFalse(repl.IsPull); Assert.IsFalse(repl.Continuous); Assert.IsNull(repl.Filter); Assert.IsNull(repl.FilterParams); Assert.IsNull(repl.DocIds); // TODO: CAssertNil(r1.headers); still not null! // Check that the replication hasn't started running: Assert.IsFalse(repl.IsRunning); Assert.AreEqual((int)repl.Status, (int)ReplicationStatus.Stopped); Assert.AreEqual(0, repl.CompletedChangesCount); Assert.AreEqual(0, repl.ChangesCount); Assert.IsNull(repl.LastError); RunReplication(repl); // TODO: Verify the foloowing 2 asserts. ChangesCount and CompletedChangesCount // should already be reset when the replicator stopped. Assert.IsTrue(repl.ChangesCount >= 2); Assert.IsTrue(repl.CompletedChangesCount >= 2); Assert.IsNull(repl.LastError); VerifyRemoteDocExists(remote, doc1Id); // Add doc3 documentProperties = new Dictionary <string, object>(); var doc3Id = string.Format("doc3-{0}", docIdTimestamp); var doc3 = database.GetDocument(doc3Id); documentProperties["bat"] = 677; doc3.PutProperties(documentProperties); // re-run push replication var repl2 = database.CreatePushReplication(remote); repl2.Continuous = continuous; if (!IsSyncGateway(remote)) { repl2.CreateTarget = true; } var repl2CheckedpointId = repl2.RemoteCheckpointDocID(); RunReplication(repl2); Assert.IsNull(repl2.LastError); // make sure trhe doc has been added VerifyRemoteDocExists(remote, doc3Id); Assert.AreEqual(repl2.LastSequence, database.LastSequenceWithCheckpointId(repl2CheckedpointId)); System.Threading.Thread.Sleep(2000); var json = GetRemoteDoc(remote, repl2CheckedpointId); var remoteLastSequence = (string)json["lastSequence"]; Assert.AreEqual(repl2.LastSequence, remoteLastSequence); Log.D(Tag, "testPusher() finished"); }
public void TestPusherDeletedDoc() { var remote = GetReplicationURL(); var docIdTimestamp = Convert.ToString(Runtime.CurrentTimeMillis()); // Create some documentsConvert var documentProperties = new Dictionary <string, object>(); var doc1Id = string.Format("doc1-{0}", docIdTimestamp); documentProperties["_id"] = doc1Id; documentProperties["foo"] = 1; documentProperties["bar"] = false; var body = new Body(documentProperties); var rev1 = new RevisionInternal(body, database); var status = new Status(); rev1 = database.PutRevision(rev1, null, false, status); Assert.AreEqual(StatusCode.Created, status.GetCode()); documentProperties["_rev"] = rev1.GetRevId(); documentProperties["UPDATED"] = true; documentProperties["_deleted"] = true; database.PutRevision(new RevisionInternal(documentProperties, database), rev1.GetRevId(), false, status); Assert.IsTrue((int)status.GetCode() >= 200 && (int)status.GetCode() < 300); var repl = database.CreatePushReplication(remote); if (!IsSyncGateway(remote)) { ((Pusher)repl).CreateTarget = true; } RunReplication(repl); Assert.IsNull(repl.LastError); // make sure doc1 is deleted var replicationUrlTrailing = new Uri(string.Format("{0}/", remote)); var pathToDoc = new Uri(replicationUrlTrailing, doc1Id); Log.D(Tag, "Send http request to " + pathToDoc); var httpRequestDoneSignal = new CountDownLatch(1); var httpclient = new HttpClient(); try { var getDocResponse = httpclient.GetAsync(pathToDoc.ToString()).Result; var statusLine = getDocResponse.StatusCode; Log.D(ReplicationTest.Tag, "statusLine " + statusLine); Assert.AreEqual(Couchbase.Lite.StatusCode.NotFound, statusLine.GetStatusCode()); } catch (ProtocolViolationException e) { Assert.IsNull(e, "Got ClientProtocolException: " + e.Message); } catch (IOException e) { Assert.IsNull(e, "Got IOException: " + e.Message); } finally { httpRequestDoneSignal.CountDown(); } Log.D(Tag, "Waiting for http request to finish"); try { httpRequestDoneSignal.Await(TimeSpan.FromSeconds(10)); Log.D(Tag, "http request finished"); } catch (Exception e) { Runtime.PrintStackTrace(e); } Log.D(Tag, "testPusherDeletedDoc() finished"); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestViewIndex() { int numTimesMapFunctionInvoked = 0; IDictionary <string, object> dict1 = new Dictionary <string, object>(); dict1["key"] = "one"; IDictionary <string, object> dict2 = new Dictionary <string, object>(); dict2["key"] = "two"; IDictionary <string, object> dict3 = new Dictionary <string, object>(); dict3["key"] = "three"; IDictionary <string, object> dictX = new Dictionary <string, object>(); dictX["clef"] = "quatre"; RevisionInternal rev1 = PutDoc(database, dict1); RevisionInternal rev2 = PutDoc(database, dict2); RevisionInternal rev3 = PutDoc(database, dict3); PutDoc(database, dictX); View view = database.GetView("aview"); var numTimesInvoked = 0; MapDelegate mapBlock = (IDictionary <string, object> document, EmitDelegate emitter) => { numTimesInvoked += 1; NUnit.Framework.Assert.IsNotNull(document["_id"]); NUnit.Framework.Assert.IsNotNull(document["_rev"]); if (document["key"] != null) { emitter(document["key"], null); } }; view.SetMap(mapBlock, "1"); NUnit.Framework.Assert.AreEqual(1, view.GetViewId()); NUnit.Framework.Assert.IsTrue(view.IsStale()); view.UpdateIndex(); IList <IDictionary <string, object> > dumpResult = view.Dump(); Log.V(Tag, "View dump: " + dumpResult); NUnit.Framework.Assert.AreEqual(3, dumpResult.Count); NUnit.Framework.Assert.AreEqual("\"one\"", dumpResult[0]["key"]); NUnit.Framework.Assert.AreEqual(1, dumpResult[0]["seq"]); NUnit.Framework.Assert.AreEqual("\"two\"", dumpResult[2]["key"]); NUnit.Framework.Assert.AreEqual(2, dumpResult[2]["seq"]); NUnit.Framework.Assert.AreEqual("\"three\"", dumpResult[1]["key"]); NUnit.Framework.Assert.AreEqual(3, dumpResult[1]["seq"]); //no-op reindex NUnit.Framework.Assert.IsFalse(view.IsStale()); view.UpdateIndex(); // Now add a doc and update a doc: RevisionInternal threeUpdated = new RevisionInternal(rev3.GetDocId(), rev3.GetRevId (), false, database); numTimesMapFunctionInvoked = mapBlock.GetNumTimesInvoked(); IDictionary <string, object> newdict3 = new Dictionary <string, object>(); newdict3["key"] = "3hree"; threeUpdated.SetProperties(newdict3); Status status = new Status(); rev3 = database.PutRevision(threeUpdated, rev3.GetRevId(), false, status); NUnit.Framework.Assert.IsTrue(status.IsSuccessful()); // Reindex again: NUnit.Framework.Assert.IsTrue(view.IsStale()); view.UpdateIndex(); // Make sure the map function was only invoked one more time (for the document that was added) NUnit.Framework.Assert.AreEqual(mapBlock.GetNumTimesInvoked(), numTimesMapFunctionInvoked + 1); IDictionary <string, object> dict4 = new Dictionary <string, object>(); dict4["key"] = "four"; RevisionInternal rev4 = PutDoc(database, dict4); RevisionInternal twoDeleted = new RevisionInternal(rev2.GetDocId(), rev2.GetRevId (), true, database); database.PutRevision(twoDeleted, rev2.GetRevId(), false, status); NUnit.Framework.Assert.IsTrue(status.IsSuccessful()); // Reindex again: NUnit.Framework.Assert.IsTrue(view.IsStale()); view.UpdateIndex(); dumpResult = view.Dump(); Log.V(Tag, "View dump: " + dumpResult); NUnit.Framework.Assert.AreEqual(3, dumpResult.Count); NUnit.Framework.Assert.AreEqual("\"one\"", dumpResult[2]["key"]); NUnit.Framework.Assert.AreEqual(1, dumpResult[2]["seq"]); NUnit.Framework.Assert.AreEqual("\"3hree\"", dumpResult[0]["key"]); NUnit.Framework.Assert.AreEqual(5, dumpResult[0]["seq"]); NUnit.Framework.Assert.AreEqual("\"four\"", dumpResult[1]["key"]); NUnit.Framework.Assert.AreEqual(6, dumpResult[1]["seq"]); // Now do a real query: IList <QueryRow> rows = view.QueryWithOptions(null); NUnit.Framework.Assert.AreEqual(3, rows.Count); NUnit.Framework.Assert.AreEqual("one", rows[2].Key); NUnit.Framework.Assert.AreEqual(rev1.GetDocId(), rows[2].DocumentId); NUnit.Framework.Assert.AreEqual("3hree", rows[0].Key); NUnit.Framework.Assert.AreEqual(rev3.GetDocId(), rows[0].DocumentId); NUnit.Framework.Assert.AreEqual("four", rows[1].Key); NUnit.Framework.Assert.AreEqual(rev4.GetDocId(), rows[1].DocumentId); view.DeleteIndex(); }
public void TestValidations() { ValidateDelegate validator = (newRevision, context) => { Assert.IsNotNull(newRevision); Assert.IsNotNull(context); Assert.IsTrue(newRevision.Properties != null || newRevision.IsDeletion); validationCalled = true; bool hoopy = newRevision.IsDeletion || (newRevision.Properties.Get("towel") != null); Log.V(ValidationsTest.Tag, string.Format("--- Validating {0} --> {1}", newRevision.Properties, hoopy)); if (!hoopy) { context.Reject("Where's your towel?"); } return(hoopy); }; database.SetValidation("hoopy", validator); // POST a valid new document: IDictionary <string, object> props = new Dictionary <string, object>(); props["name"] = "Zaphod Beeblebrox"; props["towel"] = "velvet"; RevisionInternal rev = new RevisionInternal(props, database); Status status = new Status(); validationCalled = false; rev = database.PutRevision(rev, null, false, status); Assert.IsTrue(validationCalled); Assert.AreEqual(StatusCode.Created, status.GetCode()); // PUT a valid update: props["head_count"] = 3; rev.SetProperties(props); validationCalled = false; rev = database.PutRevision(rev, rev.GetRevId(), false, status); Assert.IsTrue(validationCalled); Assert.AreEqual(StatusCode.Created, status.GetCode()); // PUT an invalid update: Sharpen.Collections.Remove(props, "towel"); rev.SetProperties(props); validationCalled = false; bool gotExpectedError = false; try { rev = database.PutRevision(rev, rev.GetRevId(), false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == StatusCode.Forbidden); } Assert.IsTrue(validationCalled); Assert.IsTrue(gotExpectedError); // POST an invalid new document: props = new Dictionary <string, object>(); props["name"] = "Vogon"; props["poetry"] = true; rev = new RevisionInternal(props, database); validationCalled = false; gotExpectedError = false; try { rev = database.PutRevision(rev, null, false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == StatusCode.Forbidden); } Assert.IsTrue(validationCalled); Assert.IsTrue(gotExpectedError); // PUT a valid new document with an ID: props = new Dictionary <string, object>(); props["_id"] = "ford"; props["name"] = "Ford Prefect"; props["towel"] = "terrycloth"; rev = new RevisionInternal(props, database); validationCalled = false; rev = database.PutRevision(rev, null, false, status); Assert.IsTrue(validationCalled); Assert.AreEqual("ford", rev.GetDocId()); // DELETE a document: rev = new RevisionInternal(rev.GetDocId(), rev.GetRevId(), true, database); Assert.IsTrue(rev.IsDeleted()); validationCalled = false; rev = database.PutRevision(rev, rev.GetRevId(), false, status); Assert.IsTrue(validationCalled); // PUT an invalid new document: props = new Dictionary <string, object>(); props["_id"] = "petunias"; props["name"] = "Pot of Petunias"; rev = new RevisionInternal(props, database); validationCalled = false; gotExpectedError = false; try { rev = database.PutRevision(rev, null, false, status); } catch (CouchbaseLiteException e) { gotExpectedError = (e.GetCBLStatus().GetCode() == StatusCode.Forbidden); } Assert.IsTrue(validationCalled); Assert.IsTrue(gotExpectedError); }
/// <exception cref="Couchbase.Lite.CouchbaseLiteException"></exception> public virtual void TestRevTree() { RevisionInternal rev = new RevisionInternal("MyDocId", "4-foxy", false, database); IDictionary <string, object> revProperties = new Dictionary <string, object>(); revProperties.Put("_id", rev.GetDocId()); revProperties.Put("_rev", rev.GetRevId()); revProperties["message"] = "hi"; rev.SetProperties(revProperties); IList <string> revHistory = new AList <string>(); revHistory.AddItem(rev.GetRevId()); revHistory.AddItem("3-thrice"); revHistory.AddItem("2-too"); revHistory.AddItem("1-won"); database.ForceInsert(rev, revHistory, null); NUnit.Framework.Assert.AreEqual(1, database.DocumentCount); VerifyHistory(database, rev, revHistory); RevisionInternal conflict = new RevisionInternal("MyDocId", "5-epsilon", false, database ); IDictionary <string, object> conflictProperties = new Dictionary <string, object>(); conflictProperties.Put("_id", conflict.GetDocId()); conflictProperties.Put("_rev", conflict.GetRevId()); conflictProperties["message"] = "yo"; conflict.SetProperties(conflictProperties); IList <string> conflictHistory = new AList <string>(); conflictHistory.AddItem(conflict.GetRevId()); conflictHistory.AddItem("4-delta"); conflictHistory.AddItem("3-gamma"); conflictHistory.AddItem("2-too"); conflictHistory.AddItem("1-won"); database.ForceInsert(conflict, conflictHistory, null); NUnit.Framework.Assert.AreEqual(1, database.DocumentCount); VerifyHistory(database, conflict, conflictHistory); // Add an unrelated document: RevisionInternal other = new RevisionInternal("AnotherDocID", "1-ichi", false, database ); IDictionary <string, object> otherProperties = new Dictionary <string, object>(); otherProperties["language"] = "jp"; other.SetProperties(otherProperties); IList <string> otherHistory = new AList <string>(); otherHistory.AddItem(other.GetRevId()); database.ForceInsert(other, otherHistory, null); // Fetch one of those phantom revisions with no body: RevisionInternal rev2 = database.GetDocumentWithIDAndRev(rev.GetDocId(), "2-too", EnumSet.NoneOf <TDContentOptions>()); NUnit.Framework.Assert.AreEqual(rev.GetDocId(), rev2.GetDocId()); NUnit.Framework.Assert.AreEqual("2-too", rev2.GetRevId()); //Assert.assertNull(rev2.getContent()); // Make sure no duplicate rows were inserted for the common revisions: NUnit.Framework.Assert.AreEqual(8, database.GetLastSequenceNumber()); // Make sure the revision with the higher revID wins the conflict: RevisionInternal current = database.GetDocumentWithIDAndRev(rev.GetDocId(), null, EnumSet.NoneOf <TDContentOptions>()); NUnit.Framework.Assert.AreEqual(conflict, current); // Get the _changes feed and verify only the winner is in it: ChangesOptions options = new ChangesOptions(); RevisionList changes = database.ChangesSince(0, options, null); RevisionList expectedChanges = new RevisionList(); expectedChanges.AddItem(conflict); expectedChanges.AddItem(other); NUnit.Framework.Assert.AreEqual(changes, expectedChanges); options.SetIncludeConflicts(true); changes = database.ChangesSince(0, options, null); expectedChanges = new RevisionList(); expectedChanges.AddItem(rev); expectedChanges.AddItem(conflict); expectedChanges.AddItem(other); NUnit.Framework.Assert.AreEqual(changes, expectedChanges); }
public void TestRevTreeChangeNotification() { const string DOCUMENT_ID = "MyDocId"; var rev = new RevisionInternal(DOCUMENT_ID, "1-one", false, database); var revProperties = new Dictionary <string, object>(); revProperties["_id"] = rev.GetDocId(); revProperties["_rev"] = rev.GetRevId(); revProperties["message"] = "hi"; rev.SetProperties(revProperties); var revHistory = new List <string>(); revHistory.Add(rev.GetRevId()); EventHandler <DatabaseChangeEventArgs> handler = (sender, e) => { var changes = e.Changes.ToList(); Assert.AreEqual(1, changes.Count); var change = changes[0]; Assert.AreEqual(DOCUMENT_ID, change.DocumentId); Assert.AreEqual(rev.GetRevId(), change.RevisionId); Assert.IsTrue(change.IsCurrentRevision); Assert.IsFalse(change.IsConflict); var current = database.GetDocument(change.DocumentId).CurrentRevision; Assert.AreEqual(rev.GetRevId(), current.Id); }; database.Changed += handler; database.ForceInsert(rev, revHistory, null); database.Changed -= handler; // add two more revisions to the document var rev3 = new RevisionInternal(DOCUMENT_ID, "3-three", false, database); var rev3Properties = new Dictionary <string, object>(); rev3Properties["_id"] = rev3.GetDocId(); rev3Properties["_rev"] = rev3.GetRevId(); rev3Properties["message"] = "hi again"; rev3.SetProperties(rev3Properties); var rev3History = new List <string>(); rev3History.Add(rev3.GetRevId()); rev3History.Add("2-two"); rev3History.Add(rev.GetRevId()); handler = (sender, e) => { var changes = e.Changes.ToList(); Assert.AreEqual(1, changes.Count); var change = changes[0]; Assert.AreEqual(DOCUMENT_ID, change.DocumentId); Assert.AreEqual(rev3.GetRevId(), change.RevisionId); Assert.IsTrue(change.IsCurrentRevision); Assert.IsFalse(change.IsConflict); var doc = database.GetDocument(change.DocumentId); Assert.AreEqual(rev3.GetRevId(), doc.CurrentRevisionId); try { Assert.AreEqual(3, doc.RevisionHistory.ToList().Count); } catch (CouchbaseLiteException ex) { Assert.Fail(); } }; database.Changed += handler; database.ForceInsert(rev3, rev3History, null); database.Changed -= handler; // add a conflicting revision, with the same history length as the last revision we // inserted. Since this new revision's revID has a higher ASCII sort, it should become the // new winning revision. var conflictRev = new RevisionInternal(DOCUMENT_ID, "3-winner", false, database); var conflictProperties = new Dictionary <string, object>(); conflictProperties["_id"] = conflictRev.GetDocId(); conflictProperties["_rev"] = conflictRev.GetRevId(); conflictProperties["message"] = "winner"; conflictRev.SetProperties(conflictProperties); var conflictRevHistory = new List <string>(); conflictRevHistory.Add(conflictRev.GetRevId()); conflictRevHistory.Add("2-two"); conflictRevHistory.Add(rev.GetRevId()); handler = (sender, e) => { var changes = e.Changes.ToList(); Assert.AreEqual(1, changes.Count); var change = changes[0]; Assert.AreEqual(DOCUMENT_ID, change.DocumentId); Assert.AreEqual(conflictRev.GetRevId(), change.RevisionId); Assert.IsTrue(change.IsCurrentRevision); Assert.IsFalse(change.IsConflict); var doc = database.GetDocument(change.DocumentId); Assert.AreEqual(rev3.GetRevId(), doc.CurrentRevisionId); try { Assert.AreEqual(2, doc.ConflictingRevisions.ToList().Count); Assert.AreEqual(3, doc.RevisionHistory.ToList().Count); } catch (CouchbaseLiteException ex) { Assert.Fail(); } }; database.Changed += handler; database.ForceInsert(conflictRev, conflictRevHistory, null); database.Changed -= handler; }