0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 00:56:44 +01:00
mongodb/jstests/replsets/transaction_ops_disallowed_in_applyOps.js

112 lines
4.4 KiB
JavaScript

/**
* Test that transaction oplog entries are not accepted by the 'applyOps' command.
*
* In 4.2, there are no MongoDB backup services that rely on applyOps based mechanisms, and any
* other external tools that use applyOps should be converting transactional oplog entries to a
* non-transactional format before running them through applyOps.
*
* @tags: [uses_transactions, uses_prepare_transaction, exclude_from_large_txns]
*/
(function() {
"use strict";
load('jstests/core/txns/libs/prepare_helpers.js');
const dbName = "test";
const collName = "coll";
const rst = new ReplSetTest({
name: collName,
nodes: 1,
// Make it easy to generate multiple oplog entries per transaction.
nodeOptions: {setParameter: {maxNumberOfTransactionOperationsInSingleOplogEntry: 1}}
});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
// Initiate a session on the primary.
const sessionOptions = {
causalConsistency: false
};
const primarySession = primary.getDB(dbName).getMongo().startSession(sessionOptions);
const primarySessionDb = primarySession.getDatabase(dbName);
const primarySessionColl = primarySessionDb[collName];
// Create a collection.
assert.commandWorked(primarySessionColl.insert({}));
//
// Run transactions of different varieties and record the oplog entries they generate, so that we
// can later try to apply them via the 'applyOps' command.
//
let oplog = primary.getDB("local")["oplog.rs"];
let sessionId = primarySession.getSessionId().id;
// Run an unprepared transaction that commits.
primarySession.startTransaction();
assert.commandWorked(primarySessionColl.insert({x: 1}));
assert.commandWorked(primarySessionColl.insert({x: 2}));
assert.commandWorked(primarySession.commitTransaction_forTesting());
let txnNum = primarySession.getTxnNumber_forTesting();
let unpreparedTxnOps = oplog.find({"lsid.id": sessionId, txnNumber: txnNum}).toArray();
assert.eq(unpreparedTxnOps.length, 2, "unexpected op count: " + tojson(unpreparedTxnOps));
// Run a prepared transaction that commits.
primarySession.startTransaction();
assert.commandWorked(primarySessionColl.insert({x: 1}));
assert.commandWorked(primarySessionColl.insert({x: 2}));
let prepareTs = PrepareHelpers.prepareTransaction(primarySession);
PrepareHelpers.commitTransaction(primarySession, prepareTs);
txnNum = primarySession.getTxnNumber_forTesting();
let preparedAndCommittedTxnOps = oplog.find({"lsid.id": sessionId, txnNumber: txnNum}).toArray();
assert.eq(preparedAndCommittedTxnOps.length,
3,
"unexpected op count: " + tojson(preparedAndCommittedTxnOps));
// Run a prepared transaction that aborts.
primarySession.startTransaction();
assert.commandWorked(primarySessionColl.insert({x: 1}));
assert.commandWorked(primarySessionColl.insert({x: 2}));
PrepareHelpers.prepareTransaction(primarySession);
assert.commandWorked(primarySession.abortTransaction_forTesting());
txnNum = primarySession.getTxnNumber_forTesting();
let preparedAndAbortedTxnOps = oplog.find({"lsid.id": sessionId, txnNumber: txnNum}).toArray();
assert.eq(
preparedAndAbortedTxnOps.length, 3, "unexpected op count: " + tojson(preparedAndAbortedTxnOps));
// Clear out any documents that may have been created in the collection.
assert.commandWorked(primarySessionColl.remove({}));
//
// Now we test running the various transaction ops we captured through the 'applyOps' command.
//
let op = unpreparedTxnOps[0]; // in-progress op.
jsTestLog("Testing in-progress transaction op: " + tojson(op));
assert.commandFailedWithCode(primarySessionDb.adminCommand({applyOps: [op]}), 31056);
op = unpreparedTxnOps[1]; // implicit commit op.
jsTestLog("Testing unprepared implicit commit transaction op: " + tojson(op));
assert.commandFailedWithCode(primarySessionDb.adminCommand({applyOps: [op]}), 31240);
op = preparedAndCommittedTxnOps[1]; // implicit prepare op.
jsTestLog("Testing implicit prepare transaction op: " + tojson(op));
assert.commandFailedWithCode(primarySessionDb.adminCommand({applyOps: [op]}), 51145);
op = preparedAndCommittedTxnOps[2]; // prepared commit op.
jsTestLog("Testing prepared commit transaction op: " + tojson(op));
assert.commandFailedWithCode(primarySessionDb.adminCommand({applyOps: [op]}), 50987);
op = preparedAndAbortedTxnOps[2]; // prepared abort op.
jsTestLog("Testing prepared abort transaction op: " + tojson(op));
assert.commandFailedWithCode(primarySessionDb.adminCommand({applyOps: [op]}), 50972);
rst.stopSet();
}());