summaryrefslogtreecommitdiff
path: root/jstests/replsets/apply_ops_wc.js
blob: 33abb160804a780283c4b44a91d6e6eff003fff9 (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
127
128
129
130
131
132
133
134
135
136
137
138
/**
 * apply_ops_wc.js
 *
 * This file tests SERVER-22270 that applyOps commands should take a writeConcern.
 * This first tests that invalid write concerns cause writeConcern errors.
 * Next, it tests replication with writeConcerns of w:2 and w:majority.
 * When there are 3 nodes up in a replica set, applyOps commands succeed.
 * It then stops replication at one seconday and confirms that applyOps commands still succeed.
 * It finally stops replication at another secondary and confirms that applyOps commands fail.
 */

(function() {
"use strict";
var nodeCount = 3;
var replTest = new ReplSetTest({name: 'applyOpsWCSet', nodes: nodeCount});
replTest.startSet();
var cfg = replTest.getReplSetConfig();
cfg.settings = {};
cfg.settings.chainingAllowed = false;
replTest.initiate(cfg);

var testDB = "applyOps-wc-test";

// Get test collection.
var master = replTest.getPrimary();
var db = master.getDB(testDB);
var coll = db.apply_ops_wc;

function dropTestCollection() {
    coll.drop();
    assert.eq(0, coll.find().itcount(), "test collection not empty");
}

dropTestCollection();

// Set up the applyOps command.
var applyOpsReq = {
    applyOps: [
        {op: "i", ns: coll.getFullName(), o: {_id: 2, x: "b"}},
        {op: "i", ns: coll.getFullName(), o: {_id: 3, x: "c"}},
        {op: "i", ns: coll.getFullName(), o: {_id: 4, x: "d"}},
    ]
};

function assertApplyOpsCommandWorked(res) {
    assert.eq(3, res.applied);
    assert.commandWorkedIgnoringWriteConcernErrors(res);
    assert.eq([true, true, true], res.results);
}

function assertWriteConcernError(res) {
    assert(res.writeConcernError);
    assert(res.writeConcernError.code);
    assert(res.writeConcernError.errmsg);
}

var invalidWriteConcerns = [{w: 'invalid'}, {w: nodeCount + 1}];

function testInvalidWriteConcern(wc) {
    jsTest.log("Testing invalid write concern " + tojson(wc));

    applyOpsReq.writeConcern = wc;
    dropTestCollection();
    assert.commandWorked(coll.insert({_id: 1, x: "a"}));
    var res = coll.runCommand(applyOpsReq);
    assertApplyOpsCommandWorked(res);
    assertWriteConcernError(res);
}

// Verify that invalid write concerns yield an error.
coll.insert({_id: 1, x: "a"});
invalidWriteConcerns.forEach(testInvalidWriteConcern);

var secondaries = replTest.getSecondaries();

var majorityWriteConcerns = [
    {w: 2, wtimeout: 30000},
    {w: 'majority', wtimeout: 30000},
];

function testMajorityWriteConcerns(wc) {
    jsTest.log("Testing " + tojson(wc));

    // Reset secondaries to ensure they can replicate.
    secondaries[0].getDB('admin').runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});
    secondaries[1].getDB('admin').runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});

    // Set the writeConcern of the applyOps command.
    applyOpsReq.writeConcern = wc;

    dropTestCollection();

    // applyOps with a full replica set should succeed.
    assert.commandWorked(coll.insert({_id: 1, x: "a"}));
    var res = db.runCommand(applyOpsReq);

    assertApplyOpsCommandWorked(res);
    assert(!res.writeConcernError,
           'applyOps on a full replicaset had writeConcern error ' + tojson(res.writeConcernError));

    dropTestCollection();

    // Stop replication at one secondary.
    secondaries[0].getDB('admin').runCommand(
        {configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'});

    // applyOps should succeed with only 1 node not replicating.
    assert.commandWorked(coll.insert({_id: 1, x: "a"}));
    res = db.runCommand(applyOpsReq);

    assertApplyOpsCommandWorked(res);
    assert(!res.writeConcernError,
           'applyOps on a replicaset with 2 working nodes had writeConcern error ' +
               tojson(res.writeConcernError));

    dropTestCollection();

    // Stop replication at a second secondary.
    secondaries[1].getDB('admin').runCommand(
        {configureFailPoint: 'rsSyncApplyStop', mode: 'alwaysOn'});

    // applyOps should fail after two nodes have stopped replicating.
    assert.commandWorked(coll.insert({_id: 1, x: "a"}));
    applyOpsReq.writeConcern.wtimeout = 5000;
    res = db.runCommand(applyOpsReq);

    assertApplyOpsCommandWorked(res);
    assertWriteConcernError(res);
}

majorityWriteConcerns.forEach(testMajorityWriteConcerns);

// Allow clean shutdown
secondaries[0].getDB('admin').runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});
secondaries[1].getDB('admin').runCommand({configureFailPoint: 'rsSyncApplyStop', mode: 'off'});

replTest.stopSet();
})();