summaryrefslogtreecommitdiff
path: root/jstests/replsets/noop_write_after_read_only_txn.js
blob: e1af31550eae446d1b1e3613fc84b301ef40cd25 (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
// Do a transaction and commit with w: majority. Confirm that if there are no writes in the
// transaction, there is a noop write at the end, and confirm that commitTransaction awaits
// writeConcern majority.
//
// @tags: [uses_transactions, requires_majority_read_concern]
(function() {
"use strict";
load('jstests/libs/write_concern_util.js');

const name = "noop_write_after_read_only_txn";
const rst = new ReplSetTest({
    name: name,
    nodes: [{}, {rsConfig: {priority: 0}}],
});
rst.startSet();
rst.initiate();

const primary = rst.getPrimary();
const dbName = "test";
const testDB = primary.getDB(dbName);

// Set up the collection.
testDB.runCommand({drop: name, writeConcern: {w: "majority"}});
assert.commandWorked(testDB.getCollection(name).insert({}, {writeConcern: {w: "majority"}}));

function runTest({readConcernLevel, shouldWrite, provokeWriteConcernError}) {
    jsTestLog(`Read concern level "${readConcernLevel}", shouldWrite: ${
        shouldWrite}, provokeWriteConcernError: ${provokeWriteConcernError}`);

    const session = primary.startSession();
    const sessionDB = session.getDatabase(dbName);
    const txnOptions = {writeConcern: {w: "majority"}};
    if (readConcernLevel)
        txnOptions.readConcern = {level: readConcernLevel};

    if (provokeWriteConcernError)
        txnOptions.writeConcern.wtimeout = 1000;

    session.startTransaction(txnOptions);
    assert.commandWorked(sessionDB.runCommand({find: name}));
    if (shouldWrite)
        assert.commandWorked(sessionDB.getCollection(name).insert({}));

    if (provokeWriteConcernError)
        stopReplicationOnSecondaries(rst);

    const commitResult =
        assert.commandWorkedIgnoringWriteConcernErrors(session.commitTransaction_forTesting());

    jsTestLog(`commitResult ${tojson(commitResult)}`);
    if (provokeWriteConcernError) {
        assertWriteConcernError(commitResult);
    } else {
        assert.commandWorked(commitResult);
    }

    const entries = rst.findOplog(primary,
                                  {
                                      op: "n",
                                      ts: {$gte: commitResult.operationTime},
                                      "o.msg": /.*read-only transaction.*/
                                  },
                                  1)
                        .toArray();

    // If the transaction had a write, it should not *also* do a noop.
    if (shouldWrite) {
        assert.eq(0, entries.length, "shouldn't have written noop oplog entry");
    } else {
        assert.eq(1, entries.length, "should have written noop oplog entry");
    }

    jsTestLog("Ending session");
    session.endSession();
    restartReplSetReplication(rst);
}

for (let readConcernLevel of [null, "local", "majority", "snapshot"]) {
    for (let shouldWrite of [false, true]) {
        for (let provokeWriteConcernError of [false, true]) {
            runTest({
                readConcernLevel: readConcernLevel,
                shouldWrite: shouldWrite,
                provokeWriteConcernError: provokeWriteConcernError
            });
        }
    }
}

rst.stopSet();
}());