Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CBG-4366 enable resurrection tests #7229

Merged
merged 4 commits into from
Dec 5, 2024
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
5 changes: 5 additions & 0 deletions rest/utilities_testing_resttester.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ func (rt *RestTester) Run(name string, test func(*testing.T)) {
})
}

func (rt *RestTester) UpdateTB(t *testing.T) {
var tb testing.TB = t
rt.testingTB.Store(&tb)
}

// GetDocBody returns the doc body for the given docID. If the document is not found, t.Fail will be called.
func (rt *RestTester) GetDocBody(docID string) db.Body {
rawResponse := rt.SendAdminRequest("GET", "/{{.keyspace}}/"+docID, "")
Expand Down
5 changes: 5 additions & 0 deletions topologytest/couchbase_lite_mock_peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ func (p *CouchbaseLiteMockPeer) TB() testing.TB {
return p.t
}

// UpdateTB updates the testing.TB for the peer.
func (p *CouchbaseLiteMockPeer) UpdateTB(t *testing.T) {
p.t = t
}

// GetBackingBucket returns the backing bucket for the peer. This is always nil.
func (p *CouchbaseLiteMockPeer) GetBackingBucket() base.Bucket {
return nil
Expand Down
4 changes: 4 additions & 0 deletions topologytest/couchbase_server_peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,10 @@ func (p *CouchbaseServerPeer) TB() testing.TB {
return p.tb
}

func (p *CouchbaseServerPeer) UpdateTB(tb *testing.T) {
p.tb = tb
}

// getDocVersion returns a DocVersion from a cas and xattrs with _vv (hlv) and _sync (RevTreeID).
func getDocVersion(docID string, peer Peer, cas uint64, xattrs map[string][]byte) DocMetadata {
docVersion := DocMetadata{
Expand Down
189 changes: 101 additions & 88 deletions topologytest/hlv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,6 @@ func (t singleActorTest) collectionName() base.ScopeAndCollectionName {
return getSingleDsName()
}

// getSingleActorTestCase returns a list of test cases in the matrix for all topologies * active peers.
func getSingleActorTestCase() []singleActorTest {
var tests []singleActorTest
for _, tc := range append(simpleTopologies, Topologies...) {
for _, activePeerID := range tc.PeerNames() {
tests = append(tests, singleActorTest{topology: tc, activePeerID: activePeerID})
}
}
return tests
}

// multiActorTest represents a test case for a single actor in a given topology.
type multiActorTest struct {
topology Topology
Expand Down Expand Up @@ -118,14 +107,19 @@ func startPeerReplications(peerReplications []PeerReplication) {
func TestHLVCreateDocumentSingleActor(t *testing.T) {

base.SetUpTestLogging(t, base.LevelDebug, base.KeyCRUD, base.KeyImport, base.KeyVV)
for _, tc := range getSingleActorTestCase() {
t.Run(tc.description(), func(t *testing.T) {
peers, _ := setupTests(t, tc.topology, tc.activePeerID)

docID := getDocID(t)
docBody := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s"}`, tc.activePeerID, tc.description()))
docVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, docBody)
waitForVersionAndBody(t, tc, peers, docID, docVersion)
for _, topology := range append(simpleTopologies, Topologies...) {
t.Run(topology.description, func(t *testing.T) {
peers, _ := setupTests(t, topology)
for _, activePeerID := range topology.PeerNames() {
t.Run(fmt.Sprintf("actor=%s", activePeerID), func(t *testing.T) {
updatePeersT(t, peers)
tc := singleActorTest{topology: topology, activePeerID: activePeerID}
docID := getDocID(t)
docBody := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s"}`, activePeerID, tc.description()))
docVersion := peers[activePeerID].CreateDocument(getSingleDsName(), docID, docBody)
waitForVersionAndBody(t, tc, peers, docID, docVersion)
})
}
})
}
}
Expand All @@ -135,7 +129,7 @@ func TestHLVCreateDocumentMultiActor(t *testing.T) {

for _, tc := range getMultiActorTestCases() {
t.Run(tc.description(), func(t *testing.T) {
peers, _ := setupTests(t, tc.topology, "")
peers, _ := setupTests(t, tc.topology)

var docVersionList []BodyAndVersion

Expand Down Expand Up @@ -173,7 +167,7 @@ func TestHLVCreateDocumentMultiActorConflict(t *testing.T) {
t.Skip("We need to be able to wait for a specific version to arrive over pull replication, CBG-4257")
}
t.Run(tc.description(), func(t *testing.T) {
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)

stopPeerReplications(replications)

Expand All @@ -196,7 +190,7 @@ func TestHLVUpdateDocumentMultiActor(t *testing.T) {
if strings.Contains(tc.description(), "CBL") {
t.Skip("Skipping Couchbase Lite test, returns unexpected body in proposeChanges: [304], CBG-4257")
}
peers, _ := setupTests(t, tc.topology, "")
peers, _ := setupTests(t, tc.topology)

// grab sorted peer list and create a list to store expected version,
// doc body and the peer the write came from
Expand Down Expand Up @@ -228,25 +222,32 @@ func TestHLVUpdateDocumentMultiActor(t *testing.T) {
func TestHLVUpdateDocumentSingleActor(t *testing.T) {

base.SetUpTestLogging(t, base.LevelDebug, base.KeyCRUD, base.KeyImport, base.KeyVV)
for _, tc := range getSingleActorTestCase() {
t.Run(tc.description(), func(t *testing.T) {
if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, returns unexpected body in proposeChanges: [304], CBG-4257")
}
peers, _ := setupTests(t, tc.topology, tc.activePeerID)

docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)
for _, topology := range append(simpleTopologies, Topologies...) {
t.Run(topology.description, func(t *testing.T) {
peers, _ := setupTests(t, topology)
for _, activePeerID := range topology.PeerNames() {
t.Run(fmt.Sprintf("actor=%s", activePeerID), func(t *testing.T) {
updatePeersT(t, peers)
tc := singleActorTest{topology: topology, activePeerID: activePeerID}
if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, returns unexpected body in proposeChanges: [304], CBG-4257")
}

docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)

waitForVersionAndBody(t, tc, peers, docID, createVersion)
waitForVersionAndBody(t, tc, peers, docID, createVersion)

body2 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 2}`, tc.activePeerID, tc.description()))
updateVersion := peers[tc.activePeerID].WriteDocument(tc.collectionName(), docID, body2)
t.Logf("createVersion: %+v, updateVersion: %+v", createVersion.docMeta, updateVersion.docMeta)
t.Logf("waiting for document version 2 on all peers")
body2 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 2}`, tc.activePeerID, tc.description()))
updateVersion := peers[tc.activePeerID].WriteDocument(tc.collectionName(), docID, body2)
t.Logf("createVersion: %+v, updateVersion: %+v", createVersion.docMeta, updateVersion.docMeta)
t.Logf("waiting for document version 2 on all peers")

waitForVersionAndBody(t, tc, peers, docID, updateVersion)
waitForVersionAndBody(t, tc, peers, docID, updateVersion)
})
}
})
}
}
Expand All @@ -272,7 +273,7 @@ func TestHLVUpdateDocumentMultiActorConflict(t *testing.T) {
t.Skip("We need to be able to wait for a specific version to arrive over pull replication + unexpected body in proposeChanges: [304] issue, CBG-4257")
}
t.Run(tc.description(), func(t *testing.T) {
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)
stopPeerReplications(replications)

docID := getDocID(t)
Expand All @@ -294,23 +295,31 @@ func TestHLVUpdateDocumentMultiActorConflict(t *testing.T) {
func TestHLVDeleteDocumentSingleActor(t *testing.T) {

base.SetUpTestLogging(t, base.LevelDebug, base.KeyImport, base.KeyVV)
for _, tc := range getSingleActorTestCase() {
t.Run(tc.description(), func(t *testing.T) {
if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}
peers, _ := setupTests(t, tc.topology, tc.activePeerID)

docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)
for _, topology := range append(simpleTopologies, Topologies...) {
t.Run(topology.description, func(t *testing.T) {
peers, _ := setupTests(t, topology)
for _, activePeerID := range topology.PeerNames() {
t.Run(fmt.Sprintf("actor=%s", activePeerID), func(t *testing.T) {
updatePeersT(t, peers)
tc := singleActorTest{topology: topology, activePeerID: activePeerID}

waitForVersionAndBody(t, tc, peers, docID, createVersion)
if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}

docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)

deleteVersion := peers[tc.activePeerID].DeleteDocument(tc.collectionName(), docID)
t.Logf("createVersion: %+v, deleteVersion: %+v", createVersion.docMeta, deleteVersion)
t.Logf("waiting for document deletion on all peers")
waitForDeletion(t, tc, peers, docID, tc.activePeerID)
waitForVersionAndBody(t, tc, peers, docID, createVersion)

deleteVersion := peers[tc.activePeerID].DeleteDocument(tc.collectionName(), docID)
t.Logf("createVersion: %+v, deleteVersion: %+v", createVersion.docMeta, deleteVersion)
t.Logf("waiting for document deletion on all peers")
waitForDeletion(t, tc, peers, docID, tc.activePeerID)
})
}
})
}
}
Expand All @@ -323,7 +332,7 @@ func TestHLVDeleteDocumentMultiActor(t *testing.T) {
if strings.Contains(tc.description(), "CBL") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}
peers, _ := setupTests(t, tc.topology, "")
peers, _ := setupTests(t, tc.topology)

for peerName := range peers {
docID := getDocID(t) + "_" + peerName
Expand Down Expand Up @@ -368,7 +377,7 @@ func TestHLVDeleteDocumentMultiActorConflict(t *testing.T) {
t.Skip("We need to be able to wait for a specific version to arrive over pull replication + unexpected body in proposeChanges: [304] issue, CBG-4257")
}
t.Run(tc.description(), func(t *testing.T) {
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)
stopPeerReplications(replications)

docID := getDocID(t)
Expand Down Expand Up @@ -408,7 +417,7 @@ func TestHLVUpdateDeleteDocumentMultiActorConflict(t *testing.T) {
}
t.Run(tc.description(), func(t *testing.T) {
peerList := tc.PeerNames()
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)
stopPeerReplications(replications)

docID := getDocID(t)
Expand Down Expand Up @@ -453,7 +462,7 @@ func TestHLVDeleteUpdateDocumentMultiActorConflict(t *testing.T) {
}
t.Run(tc.description(), func(t *testing.T) {
peerList := tc.PeerNames()
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)
stopPeerReplications(replications)

docID := getDocID(t)
Expand Down Expand Up @@ -481,38 +490,43 @@ func TestHLVDeleteUpdateDocumentMultiActorConflict(t *testing.T) {
func TestHLVResurrectDocumentSingleActor(t *testing.T) {

base.SetUpTestLogging(t, base.LevelDebug, base.KeyImport, base.KeyVV)
for _, tc := range getSingleActorTestCase() {
t.Run(tc.description(), func(t *testing.T) {
if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}
t.Skip("Skipping resurection tests CBG-4366")
for _, topology := range append(simpleTopologies, Topologies...) {
t.Run(topology.description, func(t *testing.T) {
peers, _ := setupTests(t, topology)
for _, activePeerID := range topology.PeerNames() {
t.Run(fmt.Sprintf("actor=%s", activePeerID), func(t *testing.T) {
updatePeersT(t, peers)
tc := singleActorTest{topology: topology, activePeerID: activePeerID}

if strings.HasPrefix(tc.activePeerID, "cbl") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}

peers, _ := setupTests(t, tc.topology, tc.activePeerID)
docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)
waitForVersionAndBody(t, tc, peers, docID, createVersion)

docID := getDocID(t)
body1 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": 1}`, tc.activePeerID, tc.description()))
createVersion := peers[tc.activePeerID].CreateDocument(tc.collectionName(), docID, body1)
waitForVersionAndBody(t, tc, peers, docID, createVersion)

deleteVersion := peers[tc.activePeerID].DeleteDocument(tc.collectionName(), docID)
t.Logf("createVersion: %+v, deleteVersion: %+v", createVersion, deleteVersion)
t.Logf("waiting for document deletion on all peers")
waitForDeletion(t, tc, peers, docID, tc.activePeerID)

body2 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": "resurrection"}`, tc.activePeerID, tc.description()))
resurrectVersion := peers[tc.activePeerID].WriteDocument(tc.collectionName(), docID, body2)
t.Logf("createVersion: %+v, deleteVersion: %+v, resurrectVersion: %+v", createVersion.docMeta, deleteVersion, resurrectVersion.docMeta)
t.Logf("waiting for document resurrection on all peers")

// Couchbase Lite peers do not know how to push a deletion yet, so we need to filter them out CBG-4257
nonCBLPeers := make(map[string]Peer)
for peerName, peer := range peers {
if !strings.HasPrefix(peerName, "cbl") {
nonCBLPeers[peerName] = peer
}
deleteVersion := peers[tc.activePeerID].DeleteDocument(tc.collectionName(), docID)
t.Logf("createVersion: %+v, deleteVersion: %+v", createVersion, deleteVersion)
t.Logf("waiting for document deletion on all peers")
waitForDeletion(t, tc, peers, docID, tc.activePeerID)

body2 := []byte(fmt.Sprintf(`{"peer": "%s", "topology": "%s", "write": "resurrection"}`, tc.activePeerID, tc.description()))
resurrectVersion := peers[tc.activePeerID].WriteDocument(tc.collectionName(), docID, body2)
t.Logf("createVersion: %+v, deleteVersion: %+v, resurrectVersion: %+v", createVersion.docMeta, deleteVersion, resurrectVersion.docMeta)
t.Logf("waiting for document resurrection on all peers")

// Couchbase Lite peers do not know how to push a deletion yet, so we need to filter them out CBG-4257
nonCBLPeers := make(map[string]Peer)
for peerName, peer := range peers {
if !strings.HasPrefix(peerName, "cbl") {
nonCBLPeers[peerName] = peer
}
}
waitForVersionAndBody(t, tc, peers, docID, resurrectVersion)
})
}
waitForVersionAndBody(t, tc, peers, docID, resurrectVersion)
})
}
}
Expand All @@ -524,9 +538,8 @@ func TestHLVResurrectDocumentMultiActor(t *testing.T) {
if strings.Contains(tc.description(), "CBL") {
t.Skip("Skipping Couchbase Lite test, does not know how to push a deletion yet CBG-4257")
}
t.Skip("skipped resurrection test, intermittent failures CBG-4372")

peers, _ := setupTests(t, tc.topology, "")
peers, _ := setupTests(t, tc.topology)

var docVersionList []BodyAndVersion
for _, peerName := range tc.PeerNames() {
Expand Down Expand Up @@ -578,7 +591,7 @@ func TestHLVResurrectDocumentMultiActorConflict(t *testing.T) {
t.Skip("We need to be able to wait for a specific version to arrive over pull replication + unexpected body in proposeChanges: [304] issue, CBG-4257")
}
t.Run(tc.description(), func(t *testing.T) {
peers, replications := setupTests(t, tc.topology, "")
peers, replications := setupTests(t, tc.topology)
stopPeerReplications(replications)

docID := getDocID(t)
Expand Down
31 changes: 23 additions & 8 deletions topologytest/peer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,17 @@ import (
"github.com/stretchr/testify/require"
)

const (
totalWaitTime = 10 * time.Second
pollInterval = 50 * time.Millisecond
)
// totalWaitTime is the time to wait for a document on a peer. This time is low for rosmar and high for Couchbase Server.
var totalWaitTime = 3 * time.Second

// pollInterval is the time to poll to see if a document is updated on a peer
var pollInterval = 50 * time.Millisecond

func init() {
if !base.UnitTestUrlIsWalrus() {
totalWaitTime = 40 * time.Second
}
}

// Peer represents a peer in an Mobile workflow. The types of Peers are Couchbase Server, Sync Gateway, or Couchbase Lite.
type Peer interface {
Expand Down Expand Up @@ -70,6 +77,9 @@ type internalPeer interface {
// TB returns the testing.TB for the peer.
TB() testing.TB

// UpdateTB updates the testing.TB for the peer.
UpdateTB(*testing.T)

// Context returns the context for the peer.
Context() context.Context
}
Expand Down Expand Up @@ -239,14 +249,19 @@ func createPeers(t *testing.T, peersOptions map[string]PeerOptions) map[string]P
return peers
}

func updatePeersT(t *testing.T, peers map[string]Peer) {
for _, peer := range peers {
oldTB := peer.TB().(*testing.T)
t.Cleanup(func() { peer.UpdateTB(oldTB) })
peer.UpdateTB(t)
}
}

// setupTests returns a map of peers and a list of replications. The peers will be closed and the buckets will be destroyed by t.Cleanup.
func setupTests(t *testing.T, topology Topology, activePeerID string) (map[string]Peer, []PeerReplication) {
func setupTests(t *testing.T, topology Topology) (map[string]Peer, []PeerReplication) {
peers := createPeers(t, topology.peers)
replications := createPeerReplications(t, peers, topology.replications)

if topology.skipIf != nil {
topology.skipIf(t, activePeerID, peers)
}
for _, replication := range replications {
// temporarily start the replication before writing the document, limitation of CouchbaseLiteMockPeer as active peer since WriteDocument is calls PushRev
replication.Start()
Expand Down
Loading
Loading