summaryrefslogtreecommitdiff
path: root/jstests/replsets/transaction_ops_disallowed_in_applyOps.js
blob: 1856079c642c8a1cecc7897e1b7b231a49d55313 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 * 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({}, {writeConcern: {w: "majority"}}));

//
// 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();
}());