summaryrefslogtreecommitdiff
path: root/jstests
diff options
context:
space:
mode:
authorWilliam Schultz <william.schultz@mongodb.com>2019-07-02 17:22:53 -0400
committerWilliam Schultz <william.schultz@mongodb.com>2019-07-02 17:27:17 -0400
commit285c39607ee33aea0d6aff15cfaca37d0956ab50 (patch)
treea1ed0995e93a9f2ab983132afe057dce62e94dd8 /jstests
parent823c44416e3aef98796ae0aecb6f574ad71f7c94 (diff)
downloadmongo-285c39607ee33aea0d6aff15cfaca37d0956ab50.tar.gz
SERVER-39576 Remove the 'doTxn' command
Diffstat (limited to 'jstests')
-rw-r--r--jstests/auth/lib/commands_lib.js429
-rw-r--r--jstests/core/bypass_doc_validation.js15
-rw-r--r--jstests/core/collation.js49
-rw-r--r--jstests/core/json_schema/misc_validation.js20
-rw-r--r--jstests/core/txns/commands_not_allowed_in_txn.js32
-rw-r--r--jstests/core/txns/disallow_operations_on_prepared_transaction.js11
-rw-r--r--jstests/core/txns/do_txn_atomicity.js88
-rw-r--r--jstests/core/txns/do_txn_basic.js347
-rw-r--r--jstests/core/txns/statement_ids_accepted.js2
-rw-r--r--jstests/core/views/views_all_commands.js14
-rw-r--r--jstests/libs/override_methods/read_and_write_concern_helpers.js3
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"]);