diff options
author | William Schultz <william.schultz@mongodb.com> | 2019-07-02 17:22:53 -0400 |
---|---|---|
committer | William Schultz <william.schultz@mongodb.com> | 2019-07-02 17:27:17 -0400 |
commit | 285c39607ee33aea0d6aff15cfaca37d0956ab50 (patch) | |
tree | a1ed0995e93a9f2ab983132afe057dce62e94dd8 /jstests | |
parent | 823c44416e3aef98796ae0aecb6f574ad71f7c94 (diff) | |
download | mongo-285c39607ee33aea0d6aff15cfaca37d0956ab50.tar.gz |
SERVER-39576 Remove the 'doTxn' command
Diffstat (limited to 'jstests')
-rw-r--r-- | jstests/auth/lib/commands_lib.js | 429 | ||||
-rw-r--r-- | jstests/core/bypass_doc_validation.js | 15 | ||||
-rw-r--r-- | jstests/core/collation.js | 49 | ||||
-rw-r--r-- | jstests/core/json_schema/misc_validation.js | 20 | ||||
-rw-r--r-- | jstests/core/txns/commands_not_allowed_in_txn.js | 32 | ||||
-rw-r--r-- | jstests/core/txns/disallow_operations_on_prepared_transaction.js | 11 | ||||
-rw-r--r-- | jstests/core/txns/do_txn_atomicity.js | 88 | ||||
-rw-r--r-- | jstests/core/txns/do_txn_basic.js | 347 | ||||
-rw-r--r-- | jstests/core/txns/statement_ids_accepted.js | 2 | ||||
-rw-r--r-- | jstests/core/views/views_all_commands.js | 14 | ||||
-rw-r--r-- | jstests/libs/override_methods/read_and_write_concern_helpers.js | 3 |
11 files changed, 1 insertions, 1009 deletions
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js index 0e036a65835..f531ff8bef1 100644 --- a/jstests/auth/lib/commands_lib.js +++ b/jstests/auth/lib/commands_lib.js @@ -3220,435 +3220,6 @@ var authCommandsLib = { ] }, { - testname: "doTxn_precondition", - command: { - doTxn: [{ - "op": "i", - "ns": firstDbName + ".x", - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - preCondition: [{ns: firstDbName + ".x", q: {x: 5}, res: []}], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.save({}); - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["find"]}, - {resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}, - ], - }, - ] - }, - { - testname: "doTxn_insert", - command: { - doTxn: [{ - "op": "i", - "ns": firstDbName + ".x", - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.save({}); - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: roles_write, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}, - ], - }, - ] - }, - { - testname: "doTxn_insert_UUID", - command: function(state) { - return { - doTxn: [{ - "op": "i", - "ns": state.collName, - "ui": state.uuid, - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - var sibling = db.getSisterDB(firstDbName); - sibling.runCommand({create: "x"}); - - return { - collName: sibling.x.getFullName(), - uuid: getUUIDFromListCollections(sibling, sibling.x.getName()) - }; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: {root: 1, restore: 1, __system: 1}, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}, - {resource: {cluster: true}, actions: ["useUUID"]} - ], - }, - ] - }, - { - testname: "doTxn_insert_with_nonexistent_UUID", - command: function(state) { - return { - doTxn: [{ - "op": "i", - "ns": state.collName, - // Given a nonexistent UUID. The command should fail. - "ui": UUID("71f1d1d7-68ca-493e-a7e9-f03c94e2e960"), - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - var sibling = db.getSisterDB(firstDbName); - sibling.runCommand({create: "x"}); - - return { - collName: sibling.x.getFullName(), - uuid: getUUIDFromListCollections(sibling, sibling.x.getName()) - }; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - // It would be an sanity check failure rather than a auth check - // failure. - expectFail: true, - runOnDb: adminDbName, - roles: {root: 1, restore: 1, __system: 1}, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}, - {resource: {cluster: true}, actions: ["useUUID"]} - ], - }, - ] - }, - { - testname: "doTxn_insert_UUID_failure", - command: function(state) { - return { - doTxn: [{ - "op": "i", - "ns": state.collName, - "ui": state.uuid, - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - var sibling = db.getSisterDB(firstDbName); - sibling.runCommand({create: "x"}); - - return { - collName: sibling.x.getFullName(), - uuid: getUUIDFromListCollections(sibling, sibling.x.getName()) - }; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - expectAuthzFailure: true, - runOnDb: adminDbName, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["insert"]}, - // Don't have useUUID privilege. - ], - }, - ] - }, - { - testname: "doTxn_insert_UUID_with_wrong_ns", - command: function(state) { - return { - doTxn: [{ - "op": "i", - "ns": - firstDbName + ".y", // Specify wrong name but correct uuid. Should work. - "ui": state.x_uuid, // The insert should on x - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.drop(); - db.getSisterDB(firstDbName).y.drop(); - var sibling = db.getSisterDB(firstDbName); - sibling.runCommand({create: "x"}); - sibling.runCommand({create: "y"}); - return {x_uuid: getUUIDFromListCollections(sibling, sibling.x.getName())}; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - privileges: [ - { - resource: {db: firstDbName, collection: "x"}, - actions: ["createCollection", "insert"] - }, - {resource: {db: firstDbName, collection: "y"}, actions: ["createCollection"]}, - {resource: {cluster: true}, actions: ["useUUID", "forceUUID"]} - ], - }, - ] - }, - { - testname: "doTxn_insert_UUID_with_wrong_ns_failure", - command: function(state) { - return { - doTxn: [{ - "op": "i", - "ns": - firstDbName + ".y", // Specify wrong name but correct uuid. Should work. - "ui": state.x_uuid, // The insert should on x - "o": {"_id": ObjectId("57dc3d7da4fce4358afa85b8"), "data": 5} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.drop(); - db.getSisterDB(firstDbName).y.drop(); - var sibling = db.getSisterDB(firstDbName); - sibling.runCommand({create: "x"}); - sibling.runCommand({create: "y"}); - return {x_uuid: getUUIDFromListCollections(sibling, sibling.x.getName())}; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - expectAuthzFailure: true, - runOnDb: adminDbName, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["createCollection"]}, - { - resource: {db: firstDbName, collection: "y"}, - actions: ["createCollection", "insert"] - }, - {resource: {cluster: true}, actions: ["useUUID", "forceUUID"]} - ], - }, - ] - }, - { - testname: "doTxn_upsert", - command: { - doTxn: [{ - "op": "u", - "ns": firstDbName + ".x", - "o2": {"_id": 1}, - "o": {"_id": 1, "data": 8} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.save({_id: 1, data: 1}); - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: Object.merge(roles_write, {restore: 0}, true), - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["update", "insert"]}, - ], - }, - ] - }, - { - testname: "doTxn_update", - command: { - doTxn: [{ - "op": "u", - "ns": firstDbName + ".x", - "o2": {"_id": 1}, - "o": {"_id": 1, "data": 8} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.save({_id: 1, data: 1}); - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: Object.merge(roles_write, {restore: 0}, true), - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["update"]}, - ], - }, - ] - }, - { - testname: "doTxn_update_UUID", - command: function(state) { - return { - doTxn: [{ - "op": "u", - "ns": state.collName, - "ui": state.uuid, - "o2": {"_id": 1}, - "o": {"_id": 1, "data": 8} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - var sibling = db.getSisterDB(firstDbName); - sibling.x.save({_id: 1, data: 1}); - - return { - collName: sibling.x.getFullName(), - uuid: getUUIDFromListCollections(sibling, sibling.x.getName()) - }; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: {root: 1, __system: 1}, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["update"]}, - {resource: {cluster: true}, actions: ["useUUID"]} - ], - }, - ] - }, - { - testname: "doTxn_update_UUID_failure", - command: function(state) { - return { - doTxn: [{ - "op": "u", - "ns": state.collName, - "ui": state.uuid, - "o2": {"_id": 1}, - "o": {"_id": 1, "data": 8} - }], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }; - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - var sibling = db.getSisterDB(firstDbName); - sibling.x.save({_id: 1, data: 1}); - - return { - collName: sibling.x.getFullName(), - uuid: getUUIDFromListCollections(sibling, sibling.x.getName()) - }; - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - expectAuthzFailure: true, - runOnDb: adminDbName, - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["update"]}, - ], - }, - ] - }, - { - testname: "doTxn_delete", - command: { - doTxn: [{"op": "d", "ns": firstDbName + ".x", "o": {"_id": 1}}], - txnNumber: NumberLong(0), - lsid: {id: UUID()} - }, - skipSharded: true, - skipUnlessReplicaSet: true, - setup: function(db) { - db.getSisterDB(firstDbName).x.save({_id: 1, data: 1}); - }, - teardown: function(db) { - db.getSisterDB(firstDbName).x.drop(); - }, - testcases: [ - { - runOnDb: adminDbName, - roles: Object.merge(roles_write, {restore: 0}, true), - privileges: [ - {resource: {db: firstDbName, collection: "x"}, actions: ["remove"]}, - ], - }, - ] - }, - { testname: "drop", command: {drop: "x"}, setup: function(db) { diff --git a/jstests/core/bypass_doc_validation.js b/jstests/core/bypass_doc_validation.js index 7a5f2389b3e..7457e13e4eb 100644 --- a/jstests/core/bypass_doc_validation.js +++ b/jstests/core/bypass_doc_validation.js @@ -11,7 +11,6 @@ * * - aggregation with $out * - applyOps (when not sharded) - * - doTxn (when not sharded) * - findAndModify * - insert * - mapReduce @@ -62,20 +61,6 @@ assert.eq(1, coll.count({_id: 9})); } - // Test doTxn with a simple insert if a replica set, not on mongos and the storage engine - // is WiredTiger. - if (FixtureHelpers.isReplSet(db) && !isMongos && isWiredTiger(db)) { - const session = db.getMongo().startSession(); - const sessionDb = session.getDatabase(myDb.getName()); - const op = [{op: 'i', ns: coll.getFullName(), o: {_id: 10}}]; - assertFailsValidation(sessionDb.runCommand( - {doTxn: op, bypassDocumentValidation: false, txnNumber: NumberLong("0")})); - assert.eq(0, coll.count({_id: 10})); - assert.commandWorked(sessionDb.runCommand( - {doTxn: op, bypassDocumentValidation: true, txnNumber: NumberLong("1")})); - assert.eq(1, coll.count({_id: 10})); - } - // Test the aggregation command with a $out stage. const outputCollName = 'bypass_output_coll'; const outputColl = myDb[outputCollName]; diff --git a/jstests/core/collation.js b/jstests/core/collation.js index 64f4a1dcc2d..8e2f0344f51 100644 --- a/jstests/core/collation.js +++ b/jstests/core/collation.js @@ -1854,55 +1854,6 @@ assert.eq(8, coll.findOne({_id: "foo"}).x); } - // doTxn - if (FixtureHelpers.isReplSet(db) && !isMongos && isWiredTiger(db)) { - const session = db.getMongo().startSession(); - const sessionDb = session.getDatabase(db.getName()); - - // Use majority write concern to clear the drop-pending that can cause lock conflicts with - // transactions. - coll.drop({writeConcern: {w: "majority"}}); - - assert.commandWorked( - db.createCollection("collation", {collation: {locale: "en_US", strength: 2}})); - assert.writeOK(coll.insert({_id: "foo", x: 5, str: "bar"})); - - // preCondition.q respects collection default collation. - assert.commandFailed(sessionDb.runCommand({ - doTxn: [{op: "u", ns: coll.getFullName(), o2: {_id: "foo"}, o: {$set: {x: 6}}}], - preCondition: [{ns: coll.getFullName(), q: {_id: "not foo"}, res: {str: "bar"}}], - txnNumber: NumberLong("0") - })); - assert.eq(5, coll.findOne({_id: "foo"}).x); - assert.commandWorked(sessionDb.runCommand({ - doTxn: [{op: "u", ns: coll.getFullName(), o2: {_id: "foo"}, o: {$set: {x: 6}}}], - preCondition: [{ns: coll.getFullName(), q: {_id: "FOO"}, res: {str: "bar"}}], - txnNumber: NumberLong("1") - })); - assert.eq(6, coll.findOne({_id: "foo"}).x); - - // preCondition.res respects collection default collation. - assert.commandFailed(sessionDb.runCommand({ - doTxn: [{op: "u", ns: coll.getFullName(), o2: {_id: "foo"}, o: {$set: {x: 7}}}], - preCondition: [{ns: coll.getFullName(), q: {_id: "foo"}, res: {str: "not bar"}}], - txnNumber: NumberLong("2") - })); - assert.eq(6, coll.findOne({_id: "foo"}).x); - assert.commandWorked(sessionDb.runCommand({ - doTxn: [{op: "u", ns: coll.getFullName(), o2: {_id: "foo"}, o: {$set: {x: 7}}}], - preCondition: [{ns: coll.getFullName(), q: {_id: "foo"}, res: {str: "BAR"}}], - txnNumber: NumberLong("3") - })); - assert.eq(7, coll.findOne({_id: "foo"}).x); - - // <operation>.o2 respects collection default collation. - assert.commandWorked(sessionDb.runCommand({ - doTxn: [{op: "u", ns: coll.getFullName(), o2: {_id: "FOO"}, o: {$set: {x: 8}}}], - txnNumber: NumberLong("4") - })); - assert.eq(8, coll.findOne({_id: "foo"}).x); - } - // Test that the collection created with the "cloneCollectionAsCapped" command inherits the // default collation of the corresponding collection. We skip running this command in a sharded // cluster because it isn't supported by mongos. diff --git a/jstests/core/json_schema/misc_validation.js b/jstests/core/json_schema/misc_validation.js index 5a126993902..830ce63cae0 100644 --- a/jstests/core/json_schema/misc_validation.js +++ b/jstests/core/json_schema/misc_validation.js @@ -10,7 +10,6 @@ * - update * - findAndModify * - applyOps - * - doTxn * - $elemMatch projection * * @tags: [ @@ -331,24 +330,5 @@ // transactions. coll.drop({writeConcern: {w: "majority"}}); assert.writeOK(coll.insert({_id: 1, a: true})); - - if (FixtureHelpers.isReplSet(db) && !isMongos && isWiredTiger(db)) { - // Test $jsonSchema in the precondition checking for doTxn. - const session = db.getMongo().startSession(); - const sessionDb = session.getDatabase(testDB.getName()); - res = sessionDb.adminCommand({ - doTxn: [ - {op: "u", ns: coll.getFullName(), o2: {_id: 1}, o: {$set: {a: false}}}, - ], - preCondition: [{ - ns: coll.getFullName(), - q: {$jsonSchema: {properties: {a: {type: "boolean"}}}}, - res: {a: true} - }], - txnNumber: NumberLong("0") - }); - assert.commandWorked(res); - assert.eq(1, res.applied); - } } }()); diff --git a/jstests/core/txns/commands_not_allowed_in_txn.js b/jstests/core/txns/commands_not_allowed_in_txn.js index d7ae9e51698..8583f6db9de 100644 --- a/jstests/core/txns/commands_not_allowed_in_txn.js +++ b/jstests/core/txns/commands_not_allowed_in_txn.js @@ -134,38 +134,6 @@ commands.forEach(testCommand); // - // Test that doTxn is not allowed at positions after the first in transactions. - // - - // There is no doTxn command on mongos. - if (!isMongos) { - assert.commandWorked(sessionDb.runCommand({ - find: collName, - readConcern: {level: "snapshot"}, - txnNumber: NumberLong(++txnNumber), - stmtId: NumberInt(0), - startTransaction: true, - autocommit: false - })); - assert.commandFailedWithCode(sessionDb.runCommand({ - doTxn: [{op: "u", ns: testColl.getFullName(), o2: {_id: 0}, o: {$set: {a: 5}}}], - txnNumber: NumberLong(txnNumber), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.OperationNotSupportedInTransaction); - - // It is still possible to commit the transaction. The rejected command does not abort the - // transaction. - assert.commandWorked(sessionDb.adminCommand({ - commitTransaction: 1, - txnNumber: NumberLong(txnNumber), - stmtId: NumberInt(2), - autocommit: false - })); - } - - // // Test that a find command with the read-once cursor option is not allowed in a transaction. // assert.commandFailedWithCode(sessionDb.runCommand({ diff --git a/jstests/core/txns/disallow_operations_on_prepared_transaction.js b/jstests/core/txns/disallow_operations_on_prepared_transaction.js index 6263c4d6ccb..975116b6cfd 100644 --- a/jstests/core/txns/disallow_operations_on_prepared_transaction.js +++ b/jstests/core/txns/disallow_operations_on_prepared_transaction.js @@ -63,17 +63,6 @@ }), ErrorCodes.PreparedTransactionInProgress); - // This fails with ConflictingOperationInProgress instead of PreparedTransactionInProgress - // because doTxn is always runs with startTransaction = true. - jsTestLog("Test that you can't run doTxn on a prepared transaction."); - assert.commandFailedWithCode(sessionDB.runCommand({ - doTxn: [{op: "u", ns: testColl.getFullName(), o2: {_id: 0}, o: {$set: {a: 5}}}], - txnNumber: NumberLong(session.getTxnNumber_forTesting()), - stmtId: NumberInt(1), - autocommit: false - }), - ErrorCodes.OperationNotSupportedInTransaction); - jsTestLog("Test that you can't run find on a prepared transaction."); assert.commandFailedWithCode(assert.throws(function() { sessionColl.find({}).toArray(); diff --git a/jstests/core/txns/do_txn_atomicity.js b/jstests/core/txns/do_txn_atomicity.js deleted file mode 100644 index 59307a4641b..00000000000 --- a/jstests/core/txns/do_txn_atomicity.js +++ /dev/null @@ -1,88 +0,0 @@ -// @tags: [uses_transactions] - -// Tests that doTxn is atomic for CRUD operations -(function() { - 'use strict'; - - var session = db.getMongo().startSession(); - var sessionDb = session.getDatabase("test"); - var txnNumber = 0; - - var t = db.doTxn; - t.drop({writeConcern: {w: "majority"}}); - assert.writeOK(t.insert({_id: 1})); - - // Operations including commands are not allowed and should be rejected completely. - assert.commandFailedWithCode(sessionDb.adminCommand({ - doTxn: [ - {op: 'i', ns: t.getFullName(), o: {_id: ObjectId(), x: 1}}, - {op: 'c', ns: "invalid", o: {create: "t"}}, - ], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.InvalidOptions); - assert.eq(t.count({x: 1}), 0); - - // Operations only including CRUD commands should be atomic, so the next insert will fail. - assert.commandFailedWithCode(sessionDb.adminCommand({ - doTxn: [ - {op: 'i', ns: t.getFullName(), o: {_id: ObjectId(), x: 1}}, - {op: 'i', ns: "invalid", o: {_id: ObjectId(), x: 1}}, - ], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.InvalidNamespace); - assert.eq(t.count({x: 1}), 0); - - // Operations on non-existent databases cannot be atomic. - var newDBName = "do_txn_atomicity"; - var newDB = sessionDb.getSiblingDB(newDBName); - assert.commandWorked(newDB.dropDatabase()); - // Updates on a non-existent database no longer implicitly create collections and will fail with - // a NamespaceNotFound error. - assert.commandFailedWithCode(newDB.runCommand({ - doTxn: [{op: "u", ns: newDBName + ".foo", o: {_id: 5, x: 17}, o2: {_id: 5, x: 16}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.NamespaceNotFound); - - var sawTooManyLocksError = false; - - function applyWithManyLocks(n) { - let cappedOps = []; - let multiOps = []; - - for (let i = 0; i < n; i++) { - // Write to a capped collection, as that may require a lock for serialization. - let cappedName = "capped" + n + "-" + i; - assert.commandWorked(newDB.createCollection(cappedName, {capped: true, size: 100})); - cappedOps.push({op: 'i', ns: newDBName + "." + cappedName, o: {_id: 0}}); - - // Make an index multi-key, as that may require a lock for updating the catalog. - let multiName = "multi" + n + "-" + i; - assert.commandWorked(newDB[multiName].createIndex({x: 1})); - multiOps.push({op: 'i', ns: newDBName + "." + multiName, o: {_id: 0, x: [0, 1]}}); - } - - let res = [cappedOps, multiOps].map( - (doTxn) => newDB.runCommand({doTxn: doTxn, txnNumber: NumberLong(txnNumber++)})); - sawTooManyLocksError |= res.some((res) => res.code === ErrorCodes.TooManyLocks); - // Transactions involving just two collections should succeed. - if (n <= 2) - res.every((res) => res.ok); - // All transactions should either completely succeed or completely fail. - assert(res.every((res) => res.results.every((result) => result == res.ok))); - assert(res.every((res) => !res.ok || res.applied == n)); - } - - // Try requiring different numbers of collection accesses in a single operation to cover - // all edge cases, so we run out of available locks in different code paths such as during - // oplog application. - applyWithManyLocks(1); - applyWithManyLocks(2); - - for (let i = 9; i < 20; i++) { - applyWithManyLocks(i); - } - assert(!sawTooManyLocksError, "test should not exhaust the max number of locks held at once"); -})(); diff --git a/jstests/core/txns/do_txn_basic.js b/jstests/core/txns/do_txn_basic.js deleted file mode 100644 index 1325db840b5..00000000000 --- a/jstests/core/txns/do_txn_basic.js +++ /dev/null @@ -1,347 +0,0 @@ -// @tags: [uses_transactions] - -(function() { - "use strict"; - - const t = db.do_txn1; - - var session = db.getMongo().startSession(); - db = session.getDatabase("test"); - var txnNumber = 0; - - // Use majority write concern to clear the drop-pending that can cause lock conflicts with - // transactions. - t.drop({writeConcern: {w: "majority"}}); - - // - // Input validation tests - // - - jsTestLog("Empty array of operations."); - assert.commandFailedWithCode(db.adminCommand({doTxn: [], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.InvalidOptions, - 'doTxn should fail on empty array of operations'); - - jsTestLog("Non-array type for operations."); - assert.commandFailedWithCode( - db.adminCommand({doTxn: "not an array", txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.TypeMismatch, - 'doTxn should fail on non-array type for operations'); - - jsTestLog("Missing 'op' field in an operation."); - assert.commandFailedWithCode( - db.adminCommand( - {doTxn: [{ns: t.getFullName(), o: {_id: 0}}], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation without "op" field'); - - jsTestLog("Non-string 'op' field in an operation."); - assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{op: 12345, ns: t.getFullName(), o: {_id: 0}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation with non-string "op" field'); - - jsTestLog("Empty 'op' field value in an operation."); - assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{op: '', ns: t.getFullName(), o: {_id: 0}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation with empty "op" field value'); - - jsTestLog("Missing 'ns' field in an operation."); - assert.commandFailedWithCode( - db.adminCommand({doTxn: [{op: 'u', o: {_id: 0}}], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation without "ns" field'); - - jsTestLog("Missing 'o' field in an operation."); - assert.commandFailedWithCode( - db.adminCommand( - {doTxn: [{op: 'u', ns: t.getFullName()}], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation without "o" field'); - - jsTestLog("Non-string 'ns' field in an operation."); - assert.commandFailedWithCode( - db.adminCommand( - {doTxn: [{op: 'u', ns: 12345, o: {_id: 0}}], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.FailedToParse, - 'doTxn should fail on operation with non-string "ns" field'); - - jsTestLog("Missing dbname in 'ns' field."); - assert.commandFailedWithCode( - db.adminCommand( - {doTxn: [{op: 'd', ns: t.getName(), o: {_id: 1}}], txnNumber: NumberLong(txnNumber++)}), - ErrorCodes.InvalidNamespace, - 'doTxn should fail with a missing dbname in the "ns" field value'); - - jsTestLog("Empty 'ns' field value."); - assert.commandFailed( - db.adminCommand( - {doTxn: [{op: 'u', ns: '', o: {_id: 0}}], txnNumber: NumberLong(txnNumber++)}), - 'doTxn should fail with empty "ns" field value'); - - jsTestLog("Valid 'ns' field value in unknown operation type 'x'."); - assert.commandFailedWithCode( - db.adminCommand({ - doTxn: [{op: 'x', ns: t.getFullName(), o: {_id: 0}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail on unknown operation type "x" with valid "ns" value'); - - jsTestLog("Illegal operation type 'n' (no-op)."); - assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{op: 'n', ns: t.getFullName(), o: {_id: 0}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.InvalidOptions, - 'doTxn should fail on "no op" operations.'); - - jsTestLog("Illegal operation type 'c' (command)."); - assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{op: 'c', ns: t.getCollection('$cmd').getFullName(), o: {applyOps: []}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.InvalidOptions, - 'doTxn should fail on commands.'); - - jsTestLog("No transaction number in an otherwise valid operation."); - assert.commandFailedWithCode( - db.adminCommand({doTxn: [{"op": "i", "ns": t.getFullName(), "o": {_id: 5, x: 17}}]}), - ErrorCodes.InvalidOptions, - 'doTxn should fail when no transaction number is given.'); - - jsTestLog("Session IDs and transaction numbers on sub-ops are not allowed"); - jsTestLog("doTxn should fail when inner transaction contains session id."); - var lsid = {id: UUID()}; - res = assert.commandFailedWithCode( - db.runCommand({ - doTxn: [{ - op: "i", - ns: t.getFullName(), - o: {_id: 7, x: 24}, - lsid: lsid, - txnNumber: NumberLong(1), - }], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail when inner transaction contains session id.'); - - jsTestLog("doTxn should fail when inner transaction contains transaction number."); - res = assert.commandFailedWithCode( - db.runCommand({ - doTxn: [{ - op: "u", - ns: t.getFullName(), - o2: {_id: 7}, - o: {$set: {x: 25}}, - txnNumber: NumberLong(1), - }], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail when inner transaction contains transaction number.'); - - jsTestLog("doTxn should fail when inner transaction contains statement id."); - res = assert.commandFailedWithCode( - db.runCommand({ - doTxn: [{ - op: "d", - ns: t.getFullName(), - o: {_id: 7}, - stmtId: 0, - }], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail when inner transaction contains statement id.'); - - jsTestLog("Malformed operation with unexpected field 'x'."); - assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{op: 'i', ns: t.getFullName(), o: {_id: 0}, x: 1}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.FailedToParse, - 'doTxn should fail on malformed operations.'); - - assert.eq(0, t.find().count(), "Non-zero amount of documents in collection to start"); - - /** - * Test function for running CRUD operations on non-existent namespaces using various - * combinations of invalid namespaces (collection/database) - * - * Leave 'expectedErrorCode' undefined if this command is expected to run successfully. - */ - function testCrudOperationOnNonExistentNamespace(optype, o, o2, expectedErrorCode) { - expectedErrorCode = expectedErrorCode || ErrorCodes.OK; - const t2 = db.getSiblingDB('do_txn1_no_such_db').getCollection('t'); - [t, t2].forEach(coll => { - const op = {op: optype, ns: coll.getFullName(), o: o, o2: o2}; - const cmd = {doTxn: [op], txnNumber: NumberLong(txnNumber++)}; - jsTestLog('Testing doTxn on non-existent namespace: ' + tojson(cmd)); - if (expectedErrorCode === ErrorCodes.OK) { - assert.commandWorked(db.adminCommand(cmd)); - } else { - assert.commandFailedWithCode(db.adminCommand(cmd), expectedErrorCode); - } - }); - } - - // Insert, delete, and update operations on non-existent collections/databases should return - // NamespaceNotFound. - jsTestLog("testCrudOperationOnNonExistentNamespace"); - testCrudOperationOnNonExistentNamespace('i', {_id: 0}, {}, ErrorCodes.NamespaceNotFound); - testCrudOperationOnNonExistentNamespace('d', {_id: 0}, {}, ErrorCodes.NamespaceNotFound); - testCrudOperationOnNonExistentNamespace('u', {x: 0}, {_id: 0}, ErrorCodes.NamespaceNotFound); - - jsTestLog("Valid insert"); - assert.commandWorked(db.createCollection(t.getName())); - var a = assert.commandWorked(db.adminCommand({ - doTxn: [{"op": "i", "ns": t.getFullName(), "o": {_id: 5, x: 17}}], - txnNumber: NumberLong(txnNumber++) - })); - assert.eq(1, t.find().count(), "Valid insert failed"); - assert.eq(true, a.results[0], "Bad result value for valid insert"); - - jsTestLog("Duplicate insert"); - a = assert.commandFailedWithCode(db.adminCommand({ - doTxn: [{"op": "i", "ns": t.getFullName(), "o": {_id: 5, x: 17}}], - txnNumber: NumberLong(txnNumber++) - }), - ErrorCodes.DuplicateKey); - assert.eq(1, - t.find().count(), - "The number of documents changed despite the duplicate insert failing"); - assert.eq(false, a.results[0], "Bad result value for duplicate insert"); - - var o = {_id: 5, x: 17}; - assert.eq(o, t.findOne(), "Mismatching document inserted."); - - jsTestLog("doTxn should fail on insert of object with empty array element"); - // 'o' field is an empty array. - assert.commandFailed( - db.adminCommand( - {doTxn: [{op: 'i', ns: t.getFullName(), o: []}], txnNumber: NumberLong(txnNumber++)}), - 'doTxn should fail on insert of object with empty array element'); - - jsTestLog("two valid updates"); - var res = assert.commandWorked(db.runCommand({ - doTxn: [ - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 18}}}, - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 19}}} - ], - txnNumber: NumberLong(txnNumber++) - })); - - o.x++; - o.x++; - - assert.eq(1, t.find().count(), "Updates increased number of documents"); - assert.eq(o, t.findOne(), "Document doesn't match expected"); - assert.eq(true, res.results[0], "Bad result value for valid update"); - assert.eq(true, res.results[1], "Bad result value for valid update"); - - jsTestLog("preCondition fully matches"); - res = assert.commandWorked(db.runCommand({ - doTxn: [ - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 20}}}, - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 21}}} - ], - preCondition: [{ns: t.getFullName(), q: {_id: 5}, res: {x: 19}}], - txnNumber: NumberLong(txnNumber++) - })); - - o.x++; - o.x++; - - assert.eq(1, t.find().count(), "Updates increased number of documents"); - assert.eq(o, t.findOne(), "Document doesn't match expected"); - assert.eq(true, res.results[0], "Bad result value for valid update"); - assert.eq(true, res.results[1], "Bad result value for valid update"); - - jsTestLog("preCondition doesn't match ns"); - res = assert.commandFailed(db.runCommand({ - doTxn: [ - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 22}}}, - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 23}}} - ], - preCondition: [{ns: "foo.otherName", q: {_id: 5}, res: {x: 21}}], - txnNumber: NumberLong(txnNumber++) - })); - - assert.eq(o, t.findOne(), "preCondition didn't match, but ops were still applied"); - - jsTestLog("preCondition doesn't match query"); - res = assert.commandFailed(db.runCommand({ - doTxn: [ - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 22}}}, - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 23}}} - ], - preCondition: [{ns: t.getFullName(), q: {_id: 5}, res: {x: 19}}], - txnNumber: NumberLong(txnNumber++) - })); - - assert.eq(o, t.findOne(), "preCondition didn't match, but ops were still applied"); - - jsTestLog("upsert disallowed"); - res = assert.commandFailed(db.runCommand({ - doTxn: [ - {op: "u", ns: t.getFullName(), o2: {_id: 5}, o: {$set: {x: 22}}}, - {op: "u", ns: t.getFullName(), o2: {_id: 6}, o: {$set: {x: 23}}} - ], - txnNumber: NumberLong(txnNumber++) - })); - - assert.eq(false, res.results[0], "Op required upsert, which should be disallowed."); - assert.eq(false, res.results[1], "Op required upsert, which should be disallowed."); - - // When applying a "u" (update) op, we default to 'UpdateNode' update semantics, and $set - // operations add new fields in lexicographic order. - jsTestLog("$set field addition order"); - res = assert.commandWorked(db.adminCommand({ - doTxn: [ - {"op": "i", "ns": t.getFullName(), "o": {_id: 6}}, - {"op": "u", "ns": t.getFullName(), "o2": {_id: 6}, "o": {$set: {z: 1, a: 2}}} - ], - txnNumber: NumberLong(txnNumber++) - })); - assert.eq(t.findOne({_id: 6}), {_id: 6, a: 2, z: 1}); // Note: 'a' and 'z' have been sorted. - - // 'ModifierInterface' semantics are not supported, so an update with {$v: 0} should fail. - jsTestLog("Fail update with {$v:0}"); - res = assert.commandFailed(db.adminCommand({ - doTxn: [ - {"op": "i", "ns": t.getFullName(), "o": {_id: 7}}, - { - "op": "u", - "ns": t.getFullName(), - "o2": {_id: 7}, - "o": {$v: NumberLong(0), $set: {z: 1, a: 2}} - } - ], - txnNumber: NumberLong(txnNumber++), - })); - assert.eq(res.code, 40682); - - // When we explicitly specify {$v: 1}, we should get 'UpdateNode' update semantics, and $set - // operations get performed in lexicographic order. - jsTestLog("update with {$v:1}"); - res = assert.commandWorked(db.adminCommand({ - doTxn: [ - {"op": "i", "ns": t.getFullName(), "o": {_id: 8}}, - { - "op": "u", - "ns": t.getFullName(), - "o2": {_id: 8}, - "o": {$v: NumberLong(1), $set: {z: 1, a: 2}} - } - ], - txnNumber: NumberLong(txnNumber++), - })); - assert.eq(t.findOne({_id: 8}), {_id: 8, a: 2, z: 1}); // Note: 'a' and 'z' have been sorted. -})(); diff --git a/jstests/core/txns/statement_ids_accepted.js b/jstests/core/txns/statement_ids_accepted.js index 55aa90ce782..82a8e4455fb 100644 --- a/jstests/core/txns/statement_ids_accepted.js +++ b/jstests/core/txns/statement_ids_accepted.js @@ -89,8 +89,6 @@ autocommit: false })); - // The doTxn command is intentionally left out. - jsTestLog("Check that find and getmore accept a statement ID"); // Put in some data to find so getMore has a cursor to use. assert.writeOK(testColl.insert([{_id: 0}, {_id: 1}], {writeConcern: {w: "majority"}})); diff --git a/jstests/core/views/views_all_commands.js b/jstests/core/views/views_all_commands.js index 48ea40041c8..2014130b3da 100644 --- a/jstests/core/views/views_all_commands.js +++ b/jstests/core/views/views_all_commands.js @@ -200,20 +200,6 @@ dbStats: {skip: "TODO(SERVER-25948)"}, delete: {command: {delete: "view", deletes: [{q: {x: 1}, limit: 1}]}, expectFailure: true}, distinct: {command: {distinct: "view", key: "_id"}}, - doTxn: { - command: { - doTxn: [{op: "i", o: {_id: 1}, ns: "test.view"}], - txnNumber: NumberLong("0"), - lsid: {id: UUID()} - }, - expectFailure: true, - expectedErrorCode: [ - ErrorCodes.CommandNotSupportedOnView, - ErrorCodes.CommandNotSupported, - ErrorCodes.IllegalOperation - ], - skipSharded: true, - }, driverOIDTest: {skip: isUnrelated}, drop: {command: {drop: "view"}}, dropAllRolesFromDatabase: {skip: isUnrelated}, diff --git a/jstests/libs/override_methods/read_and_write_concern_helpers.js b/jstests/libs/override_methods/read_and_write_concern_helpers.js index 6581960eea5..6f7ac663357 100644 --- a/jstests/libs/override_methods/read_and_write_concern_helpers.js +++ b/jstests/libs/override_methods/read_and_write_concern_helpers.js @@ -50,7 +50,6 @@ var kCommandsSupportingWriteConcern = new Set([ "createUser", "delete", "deleteIndexes", - "doTxn", "drop", "dropAllRolesFromDatabase", "dropAllUsersFromDatabase", @@ -81,4 +80,4 @@ var kCommandsSupportingWriteConcern = new Set([ ]); var kCommandsSupportingWriteConcernInTransaction = - new Set(["doTxn", "abortTransaction", "commitTransaction"]); + new Set(["abortTransaction", "commitTransaction"]); |