Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion rest/blip_api_crud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2773,7 +2773,7 @@ func TestProcessRevIncrementsStat(t *testing.T) {
defer func() { require.NoError(t, ar.Stop()) }()

activeRT.WaitForPendingChanges()
sgrRunner.WaitForVersion(docID, activeRT, version)
sgrRunner.WaitForDocReplicated(docID, remoteRT, activeRT, version)

base.RequireWaitForStat(t, pullStats.HandleRevCount.Value, 1)
assert.NotEqualValues(t, 0, pullStats.HandleRevBytes.Value())
Expand Down
14 changes: 10 additions & 4 deletions rest/replicatortest/replicator_conflict_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2117,7 +2117,9 @@ func TestActiveReplicatorConflictRemoveCVFromCache(t *testing.T) {
newRev := db.CreateRevIDWithBytes(2, rt2Version.RevTreeID, docBodyBytes) // generate what the new revID will be after conflict resolution
conflictResVersion := rt1Version
conflictResVersion.RevTreeID = newRev
rt2.WaitForVersion(docID, conflictResVersion)
// rt1 has resolved once the result reaches rt2. Don't wait on rt1 over REST: that would populate the rev
// cache this test asserts on.
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, conflictResVersion)

// assert we cannot keep old cache entry for original wrote (before conflict resolution) on active cluster rest testers
collectionActive1, ctxActive1 := active.GetSingleTestDatabaseCollectionWithUser()
Expand Down Expand Up @@ -2172,8 +2174,9 @@ func TestActiveReplicatorV4DefaultResolverWithTombstoneLocal(t *testing.T) {
conflictResVersion := rt1Version
conflictResVersion.RevTreeID = newRev

// expect local doc to win and still be tombstone with remote docs revision history
sgrRunner.WaitForTombstone(docID, activeRT, conflictResVersion)
// expect local doc to win and still be tombstone with remote docs revision history. The local CV is new to
// passiveRT, so the resolved tombstone is pushed back.
sgrRunner.WaitForDocReplicated(docID, activeRT, passiveRT, conflictResVersion)

rt1Doc := activeRT.GetDocument(docID)
// assert that remote cv is in pv now
Expand Down Expand Up @@ -2202,6 +2205,7 @@ func TestActiveReplicatorV4DefaultResolverWithTombstoneRemote(t *testing.T) {
rt2Version := passiveRT.PutDoc(docID, `{"source":"passiveRT","channels":["alice"]}`)
rt2Version = passiveRT.DeleteDoc(docID, rt2Version)
passiveRT.WaitForPendingChanges()
passiveDocBeforeReplication := rest.ExpectedISGRDocFromPeer(t, passiveRT, docID)
// create conflicting update on activeRT
rt1Version := activeRT.PutDoc(docID, `{"source":"activeRT","channels":["alice"]}`)
// delete local version
Expand All @@ -2223,7 +2227,9 @@ func TestActiveReplicatorV4DefaultResolverWithTombstoneRemote(t *testing.T) {
newRev := getRevTreeID(t, rt1Version.RevTreeID, []byte(db.DeletedDocument))
conflictResVersion := rt2Version
conflictResVersion.RevTreeID = newRev
sgrRunner.WaitForTombstone(docID, activeRT, conflictResVersion)
sgrRunner.RequireDoc(docID, activeRT, rest.ExpectedISGRDoc{Version: conflictResVersion, Deleted: true})
// activeRT adopted passiveRT's CV, so there is nothing new to push back and passiveRT must be unchanged
sgrRunner.RequireDocUnchanged(docID, activeRT, passiveRT, activeRT.GetDatabase().SGReplicateMgr.GetActiveReplicator(replicationID), db.ActiveReplicatorTypePush, passiveDocBeforeReplication)

rt1Doc := activeRT.GetDocument(docID)
// assert that remote cv is in pv now
Expand Down
158 changes: 68 additions & 90 deletions rest/replicatortest/replicator_test.go

Large diffs are not rendered by default.

100 changes: 44 additions & 56 deletions rest/replicatortest/replicator_test_legacy_rev_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ func TestActiveReplicatorPushPullLegacyRev(t *testing.T) {
// Start the replicator
require.NoError(t, ar.Start(ctx1))

rt1.WaitForLegacyRev(docIDRT2, legacyRevRt2, []byte(`{"source":"rt2","channels":["alice"]}`))
rt2.WaitForLegacyRev(docIDRT1, legacyRevRt1, []byte(`{"source":"rt1","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docIDRT2, rt2, rt1, rest.DocVersion{RevTreeID: legacyRevRt2})
sgrRunner.WaitForDocReplicated(docIDRT1, rt1, rt2, rest.DocVersion{RevTreeID: legacyRevRt1})
})
}

Expand Down Expand Up @@ -174,32 +174,24 @@ func TestActiveReplicatorBiDirectionalPreUpgradedDocOnPeer(t *testing.T) {
require.NoError(t, ar.Start(ctx1))

if tc.newRevOnActivePeer {
rt2.WaitForLegacyRev(docID, legacyRevRT1, []byte(`{"source":"rt1","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, rest.DocVersion{RevTreeID: legacyRevRT1})
activeDocBeforePullBack := rest.ExpectedISGRDocFromPeer(t, rt1, docID)
rt2Doc := rt2.GetDocument(docID)
rest.RequireHistoryContains(t, rt2Doc.History, []string{legacyRevRT1, initLegacyRevRT1})

// add new doc for some replication activity on pull side to allow us to assert that legacy rev 2-abc added
// isn't pulled back to rt1 now it has a legacy revID encoded CV
newDocVersion := rt2.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt1.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt2

// assert that the document isn't replicated back to rt1 after legacy rev CV is written on rt2
rt1Doc := rt1.GetDocument(docID)
// assert that legacy rev 2-abc isn't pulled back to rt1 now rt2 holds it with a legacy revID encoded CV
rt1Doc := sgrRunner.RequireDocUnchanged(docID, rt2, rt1, ar, db.ActiveReplicatorTypePull, activeDocBeforePullBack)
assert.Equal(t, legacyRevRT1, rt1Doc.GetRevTreeID())
assert.Nil(t, rt1Doc.HLV)
rest.RequireHistoryContains(t, rt1Doc.History, []string{legacyRevRT1, initLegacyRevRT1})
} else {
rt1.WaitForLegacyRev(docID, legacyRevRT2, []byte(`{"source":"rt2","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docID, rt2, rt1, rest.DocVersion{RevTreeID: legacyRevRT2})
passiveDocBeforePushBack := rest.ExpectedISGRDocFromPeer(t, rt2, docID)
rt1Doc := rt1.GetDocument(docID)
rest.RequireHistoryContains(t, rt1Doc.History, []string{initLegacyRevRT2, legacyRevRT2})

// add new doc for some replication activity on push side to allow us to assert that legacy rev 2-abc added
// isn't pushed back to rt2 now it has a legacy revID encoded CV
newDocVersion := rt1.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt2.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt2

// assert that the document isn't replicated back to rt2 after legacy rev CV is written on rt1
rt2Doc := rt2.GetDocument(docID)
// assert that legacy rev 2-abc isn't pushed back to rt2 now rt1 holds it with a legacy revID encoded CV
rt2Doc := sgrRunner.RequireDocUnchanged(docID, rt1, rt2, ar, db.ActiveReplicatorTypePush, passiveDocBeforePushBack)
assert.Equal(t, legacyRevRT2, rt2Doc.GetRevTreeID())
assert.Nil(t, rt2Doc.HLV)
rest.RequireHistoryContains(t, rt2Doc.History, []string{initLegacyRevRT2, legacyRevRT2})
Expand Down Expand Up @@ -424,7 +416,7 @@ func TestActiveReplicatorBiDirectionalPreUpgradedRevInHistory(t *testing.T) {
require.NoError(t, ar.Start(ctx1))

if !tc.activePeerHasUpgradedRev {
rt1.WaitForVersion(docID, upgradedDocVersion)
sgrRunner.WaitForDocReplicated(docID, rt2, rt1, upgradedDocVersion)

rt1Doc := rt1.GetDocument(docID)
rest.RequireHistoryContains(t, rt1Doc.History, []string{legacyRevRT1, initLegacyRevRT1, upgradedRevID})
Expand All @@ -442,7 +434,7 @@ func TestActiveReplicatorBiDirectionalPreUpgradedRevInHistory(t *testing.T) {
require.JSONEq(t, expectedBody, string(actualBodyRT2))
require.JSONEq(t, expectedBody, string(actualBodyRT1))
} else {
rt2.WaitForVersion(docID, upgradedDocVersion)
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, upgradedDocVersion)

rt2Doc := rt2.GetDocument(docID)
rest.RequireHistoryContains(t, rt2Doc.History, []string{legacyRevRT2, initLegacyRevRT2, upgradedRevID})
Expand Down Expand Up @@ -530,8 +522,8 @@ func TestActiveReplicatorPushPullNewDocLegacyRevAndAllowUpdateAfter(t *testing.T
// Start the replicator
require.NoError(t, ar.Start(ctx1))

rt1.WaitForLegacyRev(docIDToPull, legacyRevRt2, []byte(`{"source":"rt2","channels":["alice"]}`))
rt2.WaitForLegacyRev(docIDToPush, legacyRevRt1, []byte(`{"source":"rt1","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docIDToPull, rt2, rt1, rest.DocVersion{RevTreeID: legacyRevRt2})
sgrRunner.WaitForDocReplicated(docIDToPush, rt1, rt2, rest.DocVersion{RevTreeID: legacyRevRt1})

// now update both docs to create a new revision on each side giving them each hlv based off their nodes source
cvVersion, err := db.LegacyRevToRevTreeEncodedVersion(legacyRevRt1)
Expand All @@ -540,7 +532,7 @@ func TestActiveReplicatorPushPullNewDocLegacyRevAndAllowUpdateAfter(t *testing.T
RevTreeID: legacyRevRt1,
}
updateVer := rt1.UpdateDoc(docIDToPush, rt1DocVersion, `{"channels": ["alice"], "source": "rt1-updated"}`)
rt2.WaitForVersion(docIDToPush, updateVer)
sgrRunner.WaitForDocReplicated(docIDToPush, rt1, rt2, updateVer)
// check rev tree encoded version is in pv
finalRT2Doc := rt2.GetDocument(docIDToPush)
assert.Equal(t, cvVersion.Value, finalRT2Doc.HLV.PreviousVersions[cvVersion.SourceID])
Expand All @@ -551,7 +543,7 @@ func TestActiveReplicatorPushPullNewDocLegacyRevAndAllowUpdateAfter(t *testing.T
RevTreeID: legacyRevRt2,
}
updateVer = rt2.UpdateDoc(docIDToPull, rt2DocVersion, `{"channels": ["alice"], "source": "rt2-updated"}`)
rt1.WaitForVersion(docIDToPull, updateVer)
sgrRunner.WaitForDocReplicated(docIDToPull, rt2, rt1, updateVer)
finalRT1Doc := rt1.GetDocument(docIDToPull)
assert.Equal(t, cvVersion.Value, finalRT1Doc.HLV.PreviousVersions[cvVersion.SourceID])

Expand Down Expand Up @@ -779,16 +771,14 @@ func TestActiveReplicatorConflictPreUpgradedVersionEachSide(t *testing.T) {
verPostConflictRes, _ = rt1.GetDoc(docID)
assert.NotEqual(c, legacyRevRT1, verPostConflictRes.RevTreeID)
}, 10*time.Second, 50*time.Millisecond)
rt2.WaitForLegacyRev(docID, verPostConflictRes.RevTreeID, []byte(`{"channels":["alice"],"source":"rt1"}`))
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, verPostConflictRes)
activeDocAfterResolution := rest.ExpectedISGRDocFromPeer(t, rt1, docID)
rt2Doc := rt2.GetDocument(docID)
rest.RequireHistoryContains(t, rt2Doc.History, []string{initLegacyRevRT2, legacyRevRT2, verPostConflictRes.RevTreeID})

// add doc for some replication activity on pull to assert that local doesn't change after remote is written with legacy CV
newDocVersion := rt2.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt1.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt1

// assert active side doc hasn't changed
rt1Doc := rt1.GetDocument(docID)
// assert active side doc doesn't change by pulling back the resolution it pushed to rt2, which rt2
// stored with a legacy CV
rt1Doc := sgrRunner.RequireDocUnchanged(docID, rt2, rt1, ar, db.ActiveReplicatorTypePull, activeDocAfterResolution)
rest.RequireDocRevTreeEqual(t, rest.DocVersion{RevTreeID: verPostConflictRes.RevTreeID}, rest.DocVersion{RevTreeID: rt1Doc.GetRevTreeID()})
tombstonedID := db.CreateRevIDWithBytes(3, legacyRevRT1, []byte(db.DeletedDocument)) // create what would be the tombstone rev id for local branch
rest.RequireHistoryContains(t, rt1Doc.History, []string{legacyRevRT1, initLegacyRevRT1, verPostConflictRes.RevTreeID, legacyRevRT2, tombstonedID})
Expand All @@ -802,17 +792,15 @@ func TestActiveReplicatorConflictPreUpgradedVersionEachSide(t *testing.T) {
return replicationStats.ConflictResolvedRemoteCount.Value()
}, 1)

rt1.WaitForLegacyRev(docID, legacyRevRT2, []byte(`{"channels":["alice"],"source":"rt2"}`))
sgrRunner.WaitForDocReplicated(docID, rt2, rt1, rest.DocVersion{RevTreeID: legacyRevRT2})
passiveDocAfterResolution := rest.ExpectedISGRDocFromPeer(t, rt2, docID)
rt1Doc := rt1.GetDocument(docID)
tombstonedID := db.CreateRevIDWithBytes(3, legacyRevRT1, []byte(db.DeletedDocument)) // create what would be the tombstone rev id for local branch
rest.RequireHistoryContains(t, rt1Doc.History, []string{initLegacyRevRT1, legacyRevRT1, legacyRevRT2, tombstonedID})

// add doc for some replication activity on push to assert that local doesn't change after remote is written with legacy CV
newDocVersion := rt1.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt2.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt2

// assert passive side doc hasn't changed
rt2Doc := rt2.GetDocument(docID)
// assert passive side doc doesn't change by rt1 pushing back the remote win, which rt1 stored with a
// legacy CV
rt2Doc := sgrRunner.RequireDocUnchanged(docID, rt1, rt2, ar, db.ActiveReplicatorTypePush, passiveDocAfterResolution)
rest.RequireDocRevTreeEqual(t, rest.DocVersion{RevTreeID: legacyRevRT2}, rest.DocVersion{RevTreeID: rt2Doc.GetRevTreeID()})
rest.RequireHistoryContains(t, rt2Doc.History, []string{initLegacyRevRT2, legacyRevRT2})
// legacy cv written to rt1 will correspond to local rev tree ID thus no HLV should be written yet
Expand Down Expand Up @@ -944,6 +932,8 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {
require.NoError(t, ar.Stop())
}()

passiveDocBeforeReplication := rest.ExpectedISGRDocFromPeer(t, rt2, docID)

// Start the replicator
require.NoError(t, ar.Start(ctx1))

Expand All @@ -961,7 +951,8 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {
assert.NotEqual(c, legacyRevRT1, verPostConflictRes.RevTreeID)
}, 10*time.Second, 50*time.Millisecond)
// wait for this resolution to be pushed back to passive peer
rt2.WaitForVersion(docID, verPostConflictRes)
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, verPostConflictRes)
activeDocAfterResolution := rest.ExpectedISGRDocFromPeer(t, rt1, docID)

// assert original upgraded version in PV history
assert.Equal(t, upgradedDocVersion.CV.Value, replicatedDoc.HLV.PreviousVersions[upgradedDocVersion.CV.SourceID])
Expand All @@ -974,12 +965,8 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {
rt2BodyBytes, err := rt2Doc.BodyBytes(rt2.Context())
require.NoError(t, err)

// add doc for some replication activity on pull to assert that local doesn't change after remote is written with legacy CV
newDocVersion := rt2.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt1.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt1

// assert active side doc hasn't changed
rt1Doc := rt1.GetDocument(docID)
// assert active side doc doesn't change by pulling back the resolution it pushed to rt2
rt1Doc := sgrRunner.RequireDocUnchanged(docID, rt2, rt1, ar, db.ActiveReplicatorTypePull, activeDocAfterResolution)
rest.RequireDocVersionEqual(t, verPostConflictRes, rt1Doc.ExtractDocVersion())
tombstonedID := db.CreateRevIDWithBytes(3, legacyRevRT1, []byte(db.DeletedDocument)) // create what would be the tombstone rev id for local branch
rest.RequireHistoryContains(t, rt1Doc.History, []string{legacyRevRT1, initLegacyRevRT1, verPostConflictRes.RevTreeID, legacyRevRT2, tombstonedID})
Expand All @@ -993,7 +980,12 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {
base.RequireWaitForStat(t, func() int64 {
return replicationStats.ConflictResolvedRemoteCount.Value()
}, 1)
rt1.WaitForVersion(docID, upgradedDocVersion)
// rt1 adopts rt2's CV and keeps its losing legacy branch in pv, so its HLV legitimately differs from rt2's
sgrRunner.RequireDoc(docID, rt1, rest.ExpectedISGRDoc{
Version: upgradedDocVersion,
Body: expectedBody,
Channels: []string{username},
})

rt1Doc := rt1.GetDocument(docID)
tombstonedID := db.CreateRevIDWithBytes(3, legacyRevRT1, []byte(db.DeletedDocument)) // create what would be the tombstone rev id for local branch
Expand All @@ -1002,12 +994,8 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {
rt1BodyBytes, err := rt1Doc.BodyBytes(rt1.Context())
require.NoError(t, err)

// add doc for some replication activity on push to assert that remote doesn't change after remote wins conflict res is done
newDocVersion := rt1.PutDoc("newdoc", `{"channels": ["alice"]}`)
rt2.WaitForVersion("newdoc", newDocVersion) // wait for it to arrive at rt2

// assert passive side doc hasn't changed
rt2Doc := rt2.GetDocument(docID)
// assert passive side doc hasn't changed - rt1 adopted its CV, so there was nothing to push back
rt2Doc := sgrRunner.RequireDocUnchanged(docID, rt1, rt2, ar, db.ActiveReplicatorTypePush, passiveDocBeforeReplication)
rest.RequireDocVersionEqual(t, upgradedDocVersion, rt2Doc.ExtractDocVersion())
rest.RequireHistoryContains(t, rt2Doc.History, []string{initLegacyRevRT2, upgradedDocVersion.RevTreeID})

Expand All @@ -1019,7 +1007,7 @@ func TestActiveReplicatorConflictPreUpgradedVersionOneSide(t *testing.T) {

// update doc on active side to ensure we can push with no conflict
updateVer := rt1.UpdateDoc(docID, upgradedDocVersion, `{"channels": ["alice"], "source": "rt1-updated"}`)
rt2.WaitForVersion(docID, updateVer)
sgrRunner.WaitForDocReplicated(docID, rt1, rt2, updateVer)
}
})
}
Expand Down Expand Up @@ -1088,7 +1076,7 @@ func TestActiveReplicatorDeltaSyncWhenBothSidesLegacy(t *testing.T) {
// Start the replicator
require.NoError(t, ar.Start(ctx1))

rt2.WaitForLegacyRev(docIDToPush, legacyRevRt1, []byte(`{"source":"rt1","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docIDToPush, rt1, rt2, rest.DocVersion{RevTreeID: legacyRevRt1})

base.RequireWaitForStat(t, func() int64 {
return replicationStats.PushDeltaSentCount.Value()
Expand Down Expand Up @@ -1144,7 +1132,7 @@ func TestDeltaSyncWhenOneSideHasEncodedCV(t *testing.T) {
// Start the replicator
require.NoError(t, ar.Start(ctx1))

rt2.WaitForLegacyRev(docIDToPush, legacyInitRevRt1, []byte(`{"source":"rt1","channels":["alice"]}`))
sgrRunner.WaitForDocReplicated(docIDToPush, rt1, rt2, rest.DocVersion{RevTreeID: legacyInitRevRt1})

// flush revision cache to remove old reference to rev 1 in rev cache
rt1.GetDatabase().FlushRevisionCacheForTest()
Expand All @@ -1154,7 +1142,7 @@ func TestDeltaSyncWhenOneSideHasEncodedCV(t *testing.T) {
// 1. update doc on rt1 to give HLV based of rt1 sourceID
// 2. push doc to rt2 with delta from rev1 to rev2
upgradeVersion := rt1.UpdateDoc(docIDToPush, db.DocVersion{RevTreeID: legacyInitRevRt1}, `{"channels": ["alice"], "source": "rt1-updated"}`)
rt1.WaitForVersion(docIDToPush, upgradeVersion)
sgrRunner.WaitForDocReplicated(docIDToPush, rt1, rt2, upgradeVersion)

base.RequireWaitForStat(t, func() int64 {
return replicationStats.PushDeltaSentCount.Value()
Expand Down
6 changes: 3 additions & 3 deletions rest/revocation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2121,9 +2121,9 @@ func TestReplicatorRevocationsFromZero(t *testing.T) {
rt1.WaitForReplicationStatus(ar.ID, db.ReplicationStateStopped)

// Be sure docs have arrived
sgrRunner.WaitForVersion("docA", rt1, docAVersion)
sgrRunner.WaitForVersion("docA1", rt1, docA1Version)
sgrRunner.WaitForVersion("docA2", rt1, docA2Version)
sgrRunner.WaitForDocReplicated("docA", rt2, rt1, docAVersion)
sgrRunner.WaitForDocReplicated("docA1", rt2, rt1, docA1Version)
sgrRunner.WaitForDocReplicated("docA2", rt2, rt1, docA2Version)

// Reset checkpoint (since 0)
require.NoError(t, ar.Reset())
Expand Down
Loading
Loading