summaryrefslogtreecommitdiff
path: root/jstests/serverless
diff options
context:
space:
mode:
authorMickey. J Winters <mickey.winters@mongodb.com>2023-04-19 20:29:59 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-04-19 22:52:06 +0000
commitd674d78896b572797df816a093ab8682ab860eca (patch)
treee55e908b3c090706b085a93cc0e1fcd5a1b18aa7 /jstests/serverless
parentb8a84c69d428492c9c003dbdb9c035133c696685 (diff)
downloadmongo-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.js58
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();