summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough/readConcern_snapshot_mongos.js
blob: a624a14c235296a8c952d78c75288e90d61228ec (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Test parsing of readConcern level 'snapshot' on mongos.
// @tags: [requires_replication,requires_sharding, uses_transactions, uses_single_shard_transaction]
(function() {
    "use strict";

    // Runs the command as the first in a multi statement txn that is aborted right after, expecting
    // success.
    function expectSuccessInTxnThenAbort(session, sessionConn, cmdObj) {
        session.startTransaction();
        assert.commandWorked(sessionConn.runCommand(cmdObj));
        session.abortTransaction();
    }

    // Runs the command as the first in a multi statement txn that is aborted right after, expecting
    // failure with the given error code.
    function expectFailInTxnThenAbort(session, sessionConn, expectedErrorCode, cmdObj) {
        session.startTransaction();
        assert.commandFailedWithCode(sessionConn.runCommand(cmdObj), expectedErrorCode);
        session.abortTransaction();
    }

    const dbName = "test";
    const collName = "coll";

    let st = new ShardingTest({shards: 1, rs: {nodes: 2}, config: 2, mongos: 1});
    let testDB = st.getDB(dbName);
    let coll = testDB.coll;

    // Insert data to create the collection.
    assert.writeOK(testDB[collName].insert({x: 1}));

    // noPassthrough tests

    // readConcern 'snapshot' is not allowed outside session context.
    assert.commandFailedWithCode(
        testDB.runCommand({find: collName, readConcern: {level: "snapshot"}}),
        ErrorCodes.InvalidOptions);

    let session = testDB.getMongo().startSession({causalConsistency: false});
    let sessionDb = session.getDatabase(dbName);

    // readConcern 'snapshot' is not allowed outside transaction context.
    assert.commandFailedWithCode(sessionDb.runCommand({
        find: collName,
        readConcern: {level: "snapshot"},
    }),
                                 ErrorCodes.InvalidOptions);

    // readConcern 'snapshot' is not allowed with 'atClusterTime'.
    let pingRes = assert.commandWorked(st.s0.adminCommand({ping: 1}));
    assert(pingRes.hasOwnProperty("$clusterTime"), tojson(pingRes));
    assert(pingRes.$clusterTime.hasOwnProperty("clusterTime"), tojson(pingRes));
    const clusterTime = pingRes.$clusterTime.clusterTime;

    expectFailInTxnThenAbort(session, sessionDb, ErrorCodes.InvalidOptions, {
        find: collName,
        readConcern: {level: "snapshot", atClusterTime: clusterTime},
    });

    // Passthrough tests. There are parts not implemented on mongod and mongos, they are tracked by
    // separate jiras

    // readConcern 'snapshot' is supported by insert on mongos in a transaction.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        insert: collName,
        documents: [{_id: "single-insert"}],
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is supported by update on mongos in a transaction.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        update: collName,
        updates: [{q: {_id: 0}, u: {$inc: {a: 1}}}],
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is supported by delete on mongos in a transaction.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        delete: collName,
        deletes: [{q: {}, limit: 1}],
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is supported by findAndModify on mongos in a transaction.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        findAndModify: collName,
        filter: {},
        update: {$set: {a: 1}},
        readConcern: {level: "snapshot"},
    });

    expectSuccessInTxnThenAbort(session, sessionDb, {
        aggregate: collName,
        pipeline: [],
        cursor: {},
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is supported by find on mongos.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        find: collName,
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is supported by distinct on mongos.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        distinct: collName,
        key: "x",
        readConcern: {level: "snapshot"},
    });

    // readConcern 'snapshot' is allowed with 'afterClusterTime'.
    expectSuccessInTxnThenAbort(session, sessionDb, {
        find: collName,
        readConcern: {level: "snapshot", afterClusterTime: clusterTime},
    });

    expectSuccessInTxnThenAbort(session, sessionDb, {
        aggregate: collName,
        pipeline: [],
        cursor: {},
        readConcern: {level: "snapshot", afterClusterTime: clusterTime},
    });

    st.stop();
}());