diff options
author | Mickey. J Winters <mickey.winters@mongodb.com> | 2023-04-19 20:29:59 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2023-04-19 22:52:06 +0000 |
commit | d674d78896b572797df816a093ab8682ab860eca (patch) | |
tree | e55e908b3c090706b085a93cc0e1fcd5a1b18aa7 /jstests/serverless | |
parent | b8a84c69d428492c9c003dbdb9c035133c696685 (diff) | |
download | mongo-d674d78896b572797df816a093ab8682ab860eca.tar.gz |
SERVER-75470 Reject change stream getMore commands after a split or merge has been committed
Diffstat (limited to 'jstests/serverless')
-rw-r--r-- | jstests/serverless/shard_split_change_collections_test.js | 58 |
1 files changed, 49 insertions, 9 deletions
diff --git a/jstests/serverless/shard_split_change_collections_test.js b/jstests/serverless/shard_split_change_collections_test.js index 8279b71a68e..d7c647ec469 100644 --- a/jstests/serverless/shard_split_change_collections_test.js +++ b/jstests/serverless/shard_split_change_collections_test.js @@ -21,12 +21,21 @@ const donorTenantConn = ChangeStreamMultitenantReplicaSetTest.getTenantConnection(donorPrimary.host, tenantIds[0]); test.donor.setChangeStreamState(donorTenantConn, true); +const donorNonMovingTenantConn = + ChangeStreamMultitenantReplicaSetTest.getTenantConnection(donorPrimary.host, ObjectId()); +test.donor.setChangeStreamState(donorNonMovingTenantConn, true); +const donorNonMovingCursor = donorNonMovingTenantConn.getDB("database").collection.watch(); + // Open a change stream and insert documents into database.collection before the split // starts. const donorCursor = donorTenantConn.getDB("database").collection.watch([]); const insertedDocs = [{_id: "tenant1_1"}, {_id: "tenant1_2"}, {_id: "tenant1_3"}]; donorTenantConn.getDB("database").collection.insertMany(insertedDocs); +// Start up a cursor to check if we can getMore after the tenant has been migrated and change +// collection is dropped. +const donorCursor2 = donorTenantConn.getDB("database").collection.watch([]); + const donorTenantSession = donorTenantConn.startSession({retryWrites: true}); const donorTenantSessionCollection = donorTenantSession.getDatabase("database").collection; assert.commandWorked(donorTenantSessionCollection.insert({_id: "tenant1_4", w: "RETRYABLE"})); @@ -54,18 +63,49 @@ const operation = test.createSplitOperation(tenantIds); assert.commandWorked(operation.commit()); assertMigrationState(donorPrimary, operation.migrationId, "committed"); -let errCode; -try { - donorTenantConn.getDB("database").collection.watch([]); -} catch (err) { - errCode = err.code; -} -assert.eq(errCode, - ErrorCodes.TenantMigrationCommitted, - "Opening a change stream on the donor after completion of a shard split should fail."); +// Test that we cannot open a new change stream after the tenant has been migrated. +assert.commandFailedWithCode( + donorTenantConn.getDB("database") + .runCommand({aggregate: "collection", cursor: {}, pipeline: [{$changeStream: {}}]}), + ErrorCodes.TenantMigrationCommitted, + "Opening a change stream on the donor after completion of a shard split should fail."); + +// Test change stream cursor behavior on the donor for a tenant which was migrated, and for one +// which remains on the donor. +assert.commandWorked( + donorNonMovingTenantConn.getDB("database") + .runCommand("getMore", {getMore: donorNonMovingCursor._cursorid, collection: "collection"}), + "Tailing a change stream for a tenant that wasn't moved by a split" + + "should not be blocked after the split was committed"); + +// Test that running a getMore on a change stream cursor after the migration commits throws a +// resumable change stream exception. +const failedGetMore = donorTenantConn.getDB("database").runCommand("getMore", { + getMore: donorCursor._cursorid, + collection: "collection" +}); +assert.commandFailedWithCode( + failedGetMore, + ErrorCodes.ResumeTenantChangeStream, + "Tailing a change stream on the donor after completion of a shard split should fail."); +assert(failedGetMore.hasOwnProperty("errorLabels")); +assert.contains("ResumableChangeStreamError", failedGetMore.errorLabels); + +// The cursor should have been deleted after the error so a getMore should fail. +assert.commandFailedWithCode( + donorTenantConn.getDB("database") + .runCommand("getMore", {getMore: donorCursor._cursorid, collection: "collection"}), + ErrorCodes.CursorNotFound); operation.forget(); +// getMore cursor to check if we can getMore after the database is dropped. +donorTenantSession.getDatabase("config")["system.change_collection"].drop(); +assert.commandFailedWithCode( + donorTenantConn.getDB("database") + .runCommand("getMore", {getMore: donorCursor2._cursorid, collection: "collection"}), + ErrorCodes.QueryPlanKilled); + const recipientRst = test.getRecipient(); const recipientPrimary = recipientRst.getPrimary(); |