diff options
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/core/txns/api_params_transaction.js | 88 | ||||
-rw-r--r-- | jstests/core/txns/transaction_continuing_cmds_refuse_api_params.js | 68 | ||||
-rw-r--r-- | jstests/noPassthrough/require_api_version.js | 25 | ||||
-rw-r--r-- | jstests/sharding/libs/mongos_api_params_util.js | 78 |
4 files changed, 167 insertions, 92 deletions
diff --git a/jstests/core/txns/api_params_transaction.js b/jstests/core/txns/api_params_transaction.js new file mode 100644 index 00000000000..a809f8a701c --- /dev/null +++ b/jstests/core/txns/api_params_transaction.js @@ -0,0 +1,88 @@ +/** + * Tests passing API parameters into transaction-continuing commands. + * @tags: [uses_transactions, requires_fcv_47] + */ + +(function() { +"use strict"; + +load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.isMongos(). + +const dbName = jsTestName(); +const collName = "test"; + +const testDB = db.getSiblingDB(dbName); +const testColl = testDB.getCollection(collName); + +testColl.drop({writeConcern: {w: "majority"}}); +assert.commandWorked( + testDB.runCommand({create: testColl.getName(), writeConcern: {w: "majority"}})); + +const apiParamCombos = [ + {}, + {apiVersion: "1"}, + {apiVersion: "1", apiDeprecationErrors: true}, + {apiVersion: "1", apiDeprecationErrors: false}, + {apiVersion: "1", apiStrict: true}, + {apiVersion: "1", apiStrict: true, apiDeprecationErrors: true}, + {apiVersion: "1", apiStrict: true, apiDeprecationErrors: false}, + {apiVersion: "1", apiStrict: false}, + {apiVersion: "1", apiStrict: false, apiDeprecationErrors: true}, + {apiVersion: "1", apiStrict: false, apiDeprecationErrors: false} +]; + +function addApiParams(obj, params) { + return Object.assign(Object.assign({}, obj), params); +} + +for (const txnInitiatingParams of apiParamCombos) { + for (const txnContinuingParams of apiParamCombos) { + for (const txnEndingCmdName of ["commitTransaction", "abortTransaction"]) { + // TODO (SERVER-56550): Remove "!txnContinuingParams.apiVersion". + const compatibleParams = + !txnContinuingParams.apiVersion || txnContinuingParams === txnInitiatingParams; + const session = db.getMongo().startSession(); + const sessionDb = session.getDatabase(dbName); + + session.startTransaction(); + assert.commandWorked(sessionDb.runCommand( + addApiParams({insert: collName, documents: [{}, {}, {}]}, txnInitiatingParams))); + + function checkCommand(db, command) { + const commandWithParams = addApiParams(command, txnContinuingParams); + jsTestLog(`Session ${session.getSessionId().id}, ` + + `initial params: ${tojson(txnInitiatingParams)}, ` + + `continuing params: ${tojson(txnContinuingParams)}, ` + + `compatible: ${tojson(compatibleParams)}`); + jsTestLog(`Command: ${tojson(commandWithParams)}`); + const reply = db.runCommand(commandWithParams); + jsTestLog(`Reply: ${tojson(reply)}`); + + if (compatibleParams) { + assert.commandWorked(reply); + } else { + assert.commandFailedWithCode(reply, ErrorCodes.APIMismatchError); + } + } + + /* + * Check "insert" with API params in a transaction. + */ + checkCommand(sessionDb, {insert: collName, documents: [{}]}); + + /* + * Check "commitTransaction" or "abortTransaction". + */ + let txnEndingCmd = {}; + txnEndingCmd[txnEndingCmdName] = 1; + Object.assign(txnEndingCmd, + {txnNumber: session.getTxnNumber_forTesting(), autocommit: false}); + + checkCommand(session.getDatabase("admin"), txnEndingCmd); + + // Clean up. + session.abortTransaction(); + } + } +} +})(); diff --git a/jstests/core/txns/transaction_continuing_cmds_refuse_api_params.js b/jstests/core/txns/transaction_continuing_cmds_refuse_api_params.js deleted file mode 100644 index 2eb11d1f4c3..00000000000 --- a/jstests/core/txns/transaction_continuing_cmds_refuse_api_params.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Tests that passing API parameters into transaction-continuing commands should fail. - * @tags: [uses_transactions, requires_fcv_47] - */ - -(function() { -"use strict"; - -load("jstests/libs/fixture_helpers.js"); // For FixtureHelpers.isMongos(). - -const errorCode = FixtureHelpers.isMongos(db) ? 4937701 : 4937700; -const commitTxnWithApiVersionErrorCode = FixtureHelpers.isMongos(db) ? 4937702 : 4937700; - -const dbName = jsTestName(); -const collName = "test"; - -const testDB = db.getSiblingDB(dbName); -const testColl = testDB.getCollection(collName); - -testColl.drop({writeConcern: {w: "majority"}}); -assert.commandWorked( - testDB.runCommand({create: testColl.getName(), writeConcern: {w: "majority"}})); - -const session = db.getMongo().startSession(); -const sessionAdminDB = session.getDatabase("admin"); -const sessionDB = session.getDatabase(dbName); -const sessionColl = sessionDB.getCollection(collName); - -const doc = { - x: 1 -}; - -session.startTransaction(); - -// Verify that the transaction-initiating command is allowed to specify an apiVersion. -assert.commandWorked(sessionColl.runCommand({insert: collName, documents: [doc], apiVersion: "1"})); - -// Verify that any transaction-continuing commands cannot specify API parameters. -assert.commandFailedWithCode( - sessionColl.runCommand({insert: collName, documents: [doc], apiVersion: "1"}), errorCode); -assert.commandFailedWithCode( - sessionColl.runCommand({insert: collName, documents: [doc], apiVersion: "1", apiStrict: false}), - errorCode); -assert.commandFailedWithCode( - sessionColl.runCommand( - {insert: collName, documents: [doc], apiVersion: "1", apiDeprecationErrors: false}), - errorCode); -let reply = sessionAdminDB.runCommand({ - commitTransaction: 1, - txnNumber: session.getTxnNumber_forTesting(), - autocommit: false, - apiVersion: "1" -}); -assert.commandFailedWithCode(reply, commitTxnWithApiVersionErrorCode); -reply = sessionAdminDB.runCommand({ - abortTransaction: 1, - txnNumber: session.getTxnNumber_forTesting(), - autocommit: false, - apiVersion: "1" -}); -assert.commandFailedWithCode(reply, errorCode); - -// Transaction-continuing commands without API parameters are allowed. -assert.commandWorked(sessionColl.runCommand({insert: collName, documents: [doc]})); - -assert.commandWorked(session.abortTransaction_forTesting()); -session.endSession(); -})(); diff --git a/jstests/noPassthrough/require_api_version.js b/jstests/noPassthrough/require_api_version.js index eefd34f21e0..2f496256897 100644 --- a/jstests/noPassthrough/require_api_version.js +++ b/jstests/noPassthrough/require_api_version.js @@ -47,8 +47,9 @@ function runTest(db, supportsTransctions, isMongos, writeConcern = {}, secondari if (supportsTransctions) { /* - * Transaction-starting commands must have apiVersion, transaction-continuing commands must - * not. + * Transaction-starting commands must have apiVersion, transaction-continuing commands may. + * + * TODO (SERVER-56550): Test that transaction-continuing commands fail *without* API params. */ const session = db.getMongo().startSession({causalConsistency: false}); const sessionDb = session.getDatabase(db.getName()); @@ -76,16 +77,8 @@ function runTest(db, supportsTransctions, isMongos, writeConcern = {}, secondari stmtId: NumberInt(2), autocommit: false })); - const commitTxnWithApiVersionErrorCode = isMongos ? 4937702 : 4937700; - assert.commandFailedWithCode(sessionDb.runCommand({ - commitTransaction: 1, - apiVersion: "1", - txnNumber: NumberLong(0), - autocommit: false - }), - commitTxnWithApiVersionErrorCode); assert.commandWorked(sessionDb.runCommand( - {commitTransaction: 1, txnNumber: NumberLong(0), autocommit: false})); + {commitTransaction: 1, apiVersion: "1", txnNumber: NumberLong(0), autocommit: false})); // Start a new txn so we can test abortTransaction. reply = sessionDb.runCommand({ @@ -97,16 +90,8 @@ function runTest(db, supportsTransctions, isMongos, writeConcern = {}, secondari autocommit: false }); assert.commandWorked(reply); - const abortTxnWithApiVersionErrorCode = isMongos ? 4937701 : 4937700; - assert.commandFailedWithCode(sessionDb.runCommand({ - abortTransaction: 1, - apiVersion: "1", - txnNumber: NumberLong(1), - autocommit: false - }), - abortTxnWithApiVersionErrorCode); assert.commandWorked(sessionDb.runCommand( - {abortTransaction: 1, txnNumber: NumberLong(1), autocommit: false})); + {abortTransaction: 1, apiVersion: "1", txnNumber: NumberLong(1), autocommit: false})); } assert.commandWorked( diff --git a/jstests/sharding/libs/mongos_api_params_util.js b/jstests/sharding/libs/mongos_api_params_util.js index 8d396fae984..34e28f34d8b 100644 --- a/jstests/sharding/libs/mongos_api_params_util.js +++ b/jstests/sharding/libs/mongos_api_params_util.js @@ -97,7 +97,38 @@ let MongosAPIParametersUtil = (function() { skip: "executes locally on mongos (not sent to any remote node)" }, {commandName: "_mergeAuthzCollections", skip: "internal API"}, - {commandName: "abortTransaction", skip: "prohibits API parameters"}, + { + commandName: "abortTransaction", + run: { + inAPIVersion1: true, + runsAgainstAdminDb: true, + shardCommandName: "abortTransaction", + permittedInTxn: false, // We handle the transaction manually in this test. + setUp: (context) => { + // Start a session and transaction. + const session = st.s0.startSession(); + context.lsid = session.getSessionId(); + const cmd = { + insert: "collection", + // A doc on each shard in the 2-shard configuration. + documents: [{_id: 1}, {_id: 21}], + lsid: context.lsid, + txnNumber: NumberLong(1), + autocommit: false, + startTransaction: true + }; + + assert.commandWorked( + st.s0.getDB("db").runCommand(Object.assign(cmd, context.apiParameters))); + }, + command: (context) => ({ + abortTransaction: 1, + lsid: context.lsid, + txnNumber: NumberLong(1), + autocommit: false + }) + } + }, { commandName: "addShard", run: { @@ -191,7 +222,38 @@ let MongosAPIParametersUtil = (function() { command: () => ({collStats: "collection"}), } }, - {commandName: "commitTransaction", skip: "prohibits API parameters"}, + { + commandName: "commitTransaction", + run: { + inAPIVersion1: true, + runsAgainstAdminDb: true, + shardCommandName: "commitTransaction", + permittedInTxn: false, // We handle the transaction manually in this test. + setUp: (context) => { + // Start a session and transaction. + const session = st.s0.startSession(); + context.lsid = session.getSessionId(); + const cmd = { + insert: "collection", + // A doc on each shard in the 2-shard configuration. + documents: [{_id: 1}, {_id: 21}], + lsid: context.lsid, + txnNumber: NumberLong(1), + autocommit: false, + startTransaction: true + }; + + assert.commandWorked( + st.s0.getDB("db").runCommand(Object.assign(cmd, context.apiParameters))); + }, + command: (context) => ({ + commitTransaction: 1, + lsid: context.lsid, + txnNumber: NumberLong(1), + autocommit: false + }) + } + }, {commandName: "compact", skip: "not allowed through mongos"}, { commandName: "configureFailPoint", @@ -1338,7 +1400,9 @@ let MongosAPIParametersUtil = (function() { } if (lastCommandInvocation === undefined) { - msg = `Primary didn't log ${commandName}`; + msg = `Primary didn't log ${commandName} with apiVersion ${apiVersion},` + + ` apiStrict ${apiStrict},` + + ` apiDeprecationErrors ${apiDeprecationErrors}.`; return false; } @@ -1441,7 +1505,13 @@ let MongosAPIParametersUtil = (function() { const configPrimary = st.configRS.getPrimary(); const shardZeroPrimary = st.rs0.getPrimary(); - const context = {}; + const context = { + apiParameters: { + apiVersion: apiVersion, + apiStrict: apiStrict, + apiDeprecationErrors: apiDeprecationErrors + } + }; if (runOrExplain.setUp) { jsTestLog(`setUp function for ${commandName}`); |