diff options
Diffstat (limited to 'jstests')
8 files changed, 385 insertions, 0 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index 6717e17e64d..7cde9677e96 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -4454,6 +4454,19 @@ var authCommandsLib = { command: {refreshSessionsInternal: []}, testcases: [{runOnDb: adminDbName, roles: {__system: 1}}], }, + { + testname: "_getNextSessionMods", + command: {_getNextSessionMods: "a-b"}, + skipSharded: true, + testcases: [ + { + runOnDb: adminDbName, + roles: {__system: 1}, + privileges: [{resource: {cluster: true}, actions: ["internal"]}], + expectFail: true + }, + ] + }, ], /************* SHARED TEST LOGIC ****************/ diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index b9c2474bf69..02d68beabda 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -76,6 +76,7 @@ _configsvrShardCollection: {skip: isAnInternalCommand}, _configsvrSetFeatureCompatibilityVersion: {skip: isAnInternalCommand}, _configsvrUpdateZoneKeyRange: {skip: isAnInternalCommand}, + _getNextSessionMods: {skip: isAnInternalCommand}, _getUserCacheGeneration: {skip: isAnInternalCommand}, _hashBSONElement: {skip: isAnInternalCommand}, _isSelf: {skip: isAnInternalCommand}, diff --git a/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js b/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js new file mode 100644 index 00000000000..c06a4cfdc9c --- /dev/null +++ b/jstests/sharding/move_chunk_find_and_modify_with_write_retryability.js @@ -0,0 +1,119 @@ +load("jstests/sharding/move_chunk_with_session_helper.js"); + +(function() { + + "use strict"; + + var checkFindAndModifyResult = function(expected, toCheck) { + assert.eq(expected.ok, toCheck.ok); + assert.eq(expected.value, toCheck.value); + + // TODO: SERVER-30532: after adding upserted, just compare the entire lastErrorObject + var expectedLE = expected.lastErrorObject; + var toCheckLE = toCheck.lastErrorObject; + + assert.neq(null, toCheckLE); + assert.eq(expected.updatedExisting, toCheck.updatedExisting); + assert.eq(expected.n, toCheck.n); + }; + + var lsid = UUID(); + var tests = [ + { + coll: 'findAndMod-upsert', + cmd: { + findAndModify: 'findAndMod-upsert', + query: {x: 60}, + update: {$inc: {y: 1}}, + new: true, + upsert: true, + lsid: {id: lsid}, + txnNumber: NumberLong(37), + }, + setup: function(coll) {}, + checkRetryResult: function(result, retryResult) { + checkFindAndModifyResult(result, retryResult); + }, + checkDocuments: function(coll) { + assert.eq(1, coll.findOne({x: 60}).y); + }, + }, + { + coll: 'findAndMod-update-preImage', + cmd: { + findAndModify: 'findAndMod-update-preImage', + query: {x: 60}, + update: {$inc: {y: 1}}, + new: false, + upsert: false, + lsid: {id: lsid}, + txnNumber: NumberLong(38), + }, + setup: function(coll) { + coll.insert({x: 60}); + }, + checkRetryResult: function(result, retryResult) { + checkFindAndModifyResult(result, retryResult); + }, + checkDocuments: function(coll) { + assert.eq(1, coll.findOne({x: 60}).y); + }, + }, + { + coll: 'findAndMod-update-postImage', + cmd: { + findAndModify: 'findAndMod-update-postImage', + query: {x: 60}, + update: {$inc: {y: 1}}, + new: true, + upsert: false, + lsid: {id: lsid}, + txnNumber: NumberLong(39), + }, + setup: function(coll) { + coll.insert({x: 60}); + }, + checkRetryResult: function(result, retryResult) { + checkFindAndModifyResult(result, retryResult); + }, + checkDocuments: function(coll) { + assert.eq(1, coll.findOne({x: 60}).y); + }, + }, + { + coll: 'findAndMod-delete', + cmd: { + findAndModify: 'findAndMod-delete', + query: {x: 10}, + remove: true, + lsid: {id: lsid}, + txnNumber: NumberLong(40), + }, + setup: function(coll) { + var bulk = coll.initializeUnorderedBulkOp(); + for (let i = 0; i < 10; i++) { + bulk.insert({x: 10}); + } + assert.writeOK(bulk.execute()); + + }, + checkRetryResult: function(result, retryResult) { + checkFindAndModifyResult(result, retryResult); + }, + checkDocuments: function(coll) { + assert.eq(9, coll.find({x: 10}).itcount()); + }, + }, + ]; + + var st = new ShardingTest({shards: {rs0: {nodes: 2}, rs1: {nodes: 2}}}); + assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); + st.ensurePrimaryShard('test', st.shard0.shardName); + + tests.forEach(function(test) { + testMoveChunkWithSession( + st, test.coll, test.cmd, test.setup, test.checkRetryResult, test.checkDocuments); + }); + + st.stop(); +})(); diff --git a/jstests/sharding/move_chunk_insert_with_write_retryability.js b/jstests/sharding/move_chunk_insert_with_write_retryability.js new file mode 100644 index 00000000000..bdbdef47000 --- /dev/null +++ b/jstests/sharding/move_chunk_insert_with_write_retryability.js @@ -0,0 +1,34 @@ +load("jstests/sharding/move_chunk_with_session_helper.js"); + +(function() { + + "use strict"; + + var st = new ShardingTest({shards: {rs0: {nodes: 2}, rs1: {nodes: 2}}}); + assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); + st.ensurePrimaryShard('test', st.shard0.shardName); + + var coll = 'insert'; + var cmd = { + insert: coll, + documents: [{x: 10}, {x: 30}], + ordered: false, + lsid: {id: UUID()}, + txnNumber: NumberLong(34), + }; + var setup = function() {}; + var checkRetryResult = function(result, retryResult) { + assert.eq(result.ok, retryResult.ok); + assert.eq(result.n, retryResult.n); + assert.eq(result.writeErrors, retryResult.writeErrors); + assert.eq(result.writeConcernErrors, retryResult.writeConcernErrors); + }; + var checkDocuments = function(coll) { + assert.eq(1, coll.find({x: 10}).itcount()); + assert.eq(1, coll.find({x: 30}).itcount()); + }; + + testMoveChunkWithSession(st, coll, cmd, setup, checkRetryResult, checkDocuments); + + st.stop(); +})(); diff --git a/jstests/sharding/move_chunk_remove_with_write_retryability.js b/jstests/sharding/move_chunk_remove_with_write_retryability.js new file mode 100644 index 00000000000..64d1f5d2dee --- /dev/null +++ b/jstests/sharding/move_chunk_remove_with_write_retryability.js @@ -0,0 +1,41 @@ +load("jstests/sharding/move_chunk_with_session_helper.js"); + +(function() { + + "use strict"; + + var st = new ShardingTest({shards: {rs0: {nodes: 2}, rs1: {nodes: 2}}}); + assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); + st.ensurePrimaryShard('test', st.shard0.shardName); + + var coll = 'delete'; + var cmd = { + delete: coll, + deletes: [{q: {x: 10}, limit: 1}, {q: {x: 20}, limit: 1}], + ordered: false, + lsid: {id: UUID()}, + txnNumber: NumberLong(36), + }; + var setup = function(coll) { + var bulk = coll.initializeUnorderedBulkOp(); + for (let i = 0; i < 10; i++) { + bulk.insert({x: 10}); + bulk.insert({x: 20}); + } + assert.writeOK(bulk.execute()); + }; + var checkRetryResult = function(result, retryResult) { + assert.eq(result.ok, retryResult.ok); + assert.eq(result.n, retryResult.n); + assert.eq(result.writeErrors, retryResult.writeErrors); + assert.eq(result.writeConcernErrors, retryResult.writeConcernErrors); + }; + var checkDocuments = function(coll) { + assert.eq(9, coll.find({x: 10}).itcount()); + assert.eq(9, coll.find({x: 20}).itcount()); + }; + + testMoveChunkWithSession(st, coll, cmd, setup, checkRetryResult, checkDocuments); + + st.stop(); +})(); diff --git a/jstests/sharding/move_chunk_update_with_write_retryability.js b/jstests/sharding/move_chunk_update_with_write_retryability.js new file mode 100644 index 00000000000..1f23db58782 --- /dev/null +++ b/jstests/sharding/move_chunk_update_with_write_retryability.js @@ -0,0 +1,44 @@ +load("jstests/sharding/move_chunk_with_session_helper.js"); + +(function() { + + "use strict"; + + var st = new ShardingTest({shards: {rs0: {nodes: 2}, rs1: {nodes: 2}}}); + assert.commandWorked(st.s.adminCommand({enableSharding: 'test'})); + st.ensurePrimaryShard('test', st.shard0.shardName); + + var coll = 'update'; + var cmd = { + update: 'update', + updates: [ + {q: {x: 10}, u: {$inc: {a: 1}}}, // in place + {q: {x: 20}, u: {$inc: {b: 1}}, upsert: true}, + {q: {x: 30}, u: {x: 30, z: 1}} // replacement + ], + ordered: false, + lsid: {id: UUID()}, + txnNumber: NumberLong(35), + }; + var setup = function(coll) { + coll.insert({x: 10}); + coll.insert({x: 30}); + }; + var checkRetryResult = function(result, retryResult) { + assert.eq(result.ok, retryResult.ok); + assert.eq(result.n, retryResult.n); + assert.eq(result.nModified, retryResult.nModified); + assert.eq(result.upserted, retryResult.upserted); + assert.eq(result.writeErrors, retryResult.writeErrors); + assert.eq(result.writeConcernErrors, retryResult.writeConcernErrors); + }; + var checkDocuments = function(coll) { + assert.eq(1, coll.findOne({x: 10}).a); + assert.eq(1, coll.findOne({x: 20}).b); + assert.eq(1, coll.findOne({x: 30}).z); + }; + + testMoveChunkWithSession(st, coll, cmd, setup, checkRetryResult, checkDocuments); + + st.stop(); +})(); diff --git a/jstests/sharding/move_chunk_with_session_helper.js b/jstests/sharding/move_chunk_with_session_helper.js new file mode 100644 index 00000000000..a320af844ca --- /dev/null +++ b/jstests/sharding/move_chunk_with_session_helper.js @@ -0,0 +1,49 @@ +load("jstests/replsets/rslib.js"); + +/** + * High level test scenario: + * 1. Shard collection. + * 2. Perform writes. + * 3. Migrate only chunk to other shard. + * 4. Retry writes. + * 5. Step down primary and wait for new primary. + * 6. Retry writes. + * 7. Migrate only chunk back to original shard. + * 8. Retry writes. + */ +var testMoveChunkWithSession = function( + st, collName, cmdObj, setupFunc, checkRetryResultFunc, checkDocumentsFunc) { + var ns = 'test.' + collName; + var testDB = st.s.getDB('test'); + var coll = testDB.getCollection(collName); + + assert.commandWorked(st.s.adminCommand({shardCollection: ns, key: {x: 1}})); + + setupFunc(coll); + var result = assert.commandWorked(testDB.runCommand(cmdObj)); + + assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {x: 0}, to: st.shard1.shardName})); + + checkRetryResultFunc(result, assert.commandWorked(testDB.runCommand(cmdObj))); + checkDocumentsFunc(coll); + + try { + st.rs1.getPrimary().adminCommand({replSetStepDown: 60, secondaryCatchUpPeriodSecs: 30}); + } catch (excep) { + print('Expected exception due to step down: ' + tojson(excep)); + } + + st.rs1.awaitNodesAgreeOnPrimary(); + awaitRSClientHosts(st.s, {host: st.rs1.getPrimary().host}, {ok: true, ismaster: true}); + + checkRetryResultFunc(result, assert.commandWorked(testDB.runCommand(cmdObj))); + checkDocumentsFunc(coll); + + // Make sure that the other shard knows about the latest primary. + awaitRSClientHosts( + st.rs0.getPrimary(), {host: st.rs1.getPrimary().host}, {ok: true, ismaster: true}); + assert.commandWorked(st.s.adminCommand({moveChunk: ns, find: {x: 0}, to: st.shard0.shardName})); + + checkRetryResultFunc(result, assert.commandWorked(testDB.runCommand(cmdObj))); + checkDocumentsFunc(coll); +}; diff --git a/jstests/sharding/write_transactions_during_migration.js b/jstests/sharding/write_transactions_during_migration.js new file mode 100644 index 00000000000..7c52628e05e --- /dev/null +++ b/jstests/sharding/write_transactions_during_migration.js @@ -0,0 +1,84 @@ +/** + * Tests that session information are properly transferred to the destination shard while + * new writes are being sent to the source shard. + */ + +load('./jstests/libs/chunk_manipulation_util.js'); + +/** + * Test outline: + * 1. Pause migration. + * 2. Perform writes and allow it to be capture via OpObserver + * 3. Unpause migration. + * 4. Retry writes and confirm that writes are not duplicated. + */ +(function() { + + "use strict"; + + var staticMongod = MongoRunner.runMongod({}); // For startParallelOps. + + var st = new ShardingTest({shards: {rs0: {nodes: 1}, rs1: {nodes: 1}}}); + st.adminCommand({enableSharding: 'test'}); + st.ensurePrimaryShard('test', st.shard0.shardName); + st.adminCommand({shardCollection: 'test.user', key: {x: 1}}); + + pauseMoveChunkAtStep(st.shard0, moveChunkStepNames.reachedSteadyState); + var joinMoveChunk = + moveChunkParallel(staticMongod, st.s.host, {x: 0}, null, 'test.user', st.shard1.shardName); + + var insertCmd = { + insert: 'user', + documents: [{x: 10}, {x: 30}], + ordered: false, + lsid: {id: UUID()}, + txnNumber: NumberLong(34), + }; + + var testDB = st.getDB('test'); + var insertResult = assert.commandWorked(testDB.runCommand(insertCmd)); + + var findAndModCmd = { + findAndModify: 'user', + query: {x: 30}, + update: {$inc: {y: 1}}, + new: true, + upsert: true, + lsid: {id: UUID()}, + txnNumber: NumberLong(37), + }; + + var findAndModifyResult = assert.commandWorked(testDB.runCommand(findAndModCmd)); + + unpauseMoveChunkAtStep(st.shard0, moveChunkStepNames.reachedSteadyState); + joinMoveChunk(); + + var insertRetryResult = assert.commandWorked(testDB.runCommand(insertCmd)); + + assert.eq(insertResult.ok, insertRetryResult.ok); + assert.eq(insertResult.n, insertRetryResult.n); + assert.eq(insertResult.writeErrors, insertRetryResult.writeErrors); + assert.eq(insertResult.writeConcernErrors, insertRetryResult.writeConcernErrors); + + assert.eq(1, testDB.user.find({x: 10}).itcount()); + assert.eq(1, testDB.user.find({x: 30}).itcount()); + + var findAndModifyRetryResult = assert.commandWorked(testDB.runCommand(findAndModCmd)); + + assert.eq(findAndModifyResult.ok, findAndModifyRetryResult.ok); + assert.eq(findAndModifyResult.value, findAndModifyRetryResult.value); + + // TODO: SERVER-30532: after adding upserted, just compare the entire lastErrorObject + var expectedLE = findAndModifyResult.lastErrorObject; + var toCheckLE = findAndModifyRetryResult.lastErrorObject; + + assert.neq(null, toCheckLE); + assert.eq(findAndModifyResult.updatedExisting, findAndModifyRetryResult.updatedExisting); + assert.eq(findAndModifyResult.n, findAndModifyRetryResult.n); + + assert.eq(1, testDB.user.findOne({x: 30}).y); + + st.stop(); + + MongoRunner.stopMongod(staticMongod); +})(); |