/** * This file tests that commands that do writes accept a write concern. This file does not test * mongos commands or user management commands, both of which are tested separately. This test * defines various database commands and what they expect to be true before and after the fact. * It then runs the commands with an invalid writeConcern and a valid writeConcern and * ensures that they succeed and fail appropriately. */ (function() { "use strict"; var replTest = new ReplSetTest({ name: 'WCSet', // Set priority of secondaries to zero to prevent spurious elections. nodes: [{}, {rsConfig: {priority: 0}}, {rsConfig: {priority: 0}}], settings: {chainingAllowed: false} }); replTest.startSet(); replTest.initiate(); var primary = replTest.getPrimary(); var dbName = "wc-test"; var db = primary.getDB(dbName); var collName = 'leaves'; var coll = db[collName]; function dropTestCollection() { replTest.awaitReplication(); coll.drop(); assert.eq(0, coll.find().itcount(), "test collection not empty"); } dropTestCollection(); var commands = []; commands.push({ req: {insert: collName, documents: [{type: 'maple'}]}, setupFunc: function() {}, confirmFunc: function() { assert.eq(coll.count({type: 'maple'}), 1); } }); commands.push({ req: {createIndexes: collName, indexes: [{key: {'type': 1}, name: 'type_index'}]}, setupFunc: function() { coll.insert({type: 'oak'}); assert.eq(coll.getIndexes().length, 1); }, confirmFunc: function() { assert.eq(coll.getIndexes().length, 2); } }); commands.push({ req: { update: collName, updates: [{ q: {type: 'oak'}, u: [{$set: {type: 'ginkgo'}}], }], writeConcern: {w: 'majority'} }, setupFunc: function() { coll.insert({type: 'oak'}); assert.eq(coll.count({type: 'ginkgo'}), 0); assert.eq(coll.count({type: 'oak'}), 1); }, confirmFunc: function() { assert.eq(coll.count({type: 'ginkgo'}), 1); assert.eq(coll.count({type: 'oak'}), 0); } }); commands.push({ req: { findAndModify: collName, query: {type: 'oak'}, update: {$set: {type: 'ginkgo'}}, writeConcern: {w: 'majority'} }, setupFunc: function() { coll.insert({type: 'oak'}); assert.eq(coll.count({type: 'ginkgo'}), 0); assert.eq(coll.count({type: 'oak'}), 1); }, confirmFunc: function() { assert.eq(coll.count({type: 'ginkgo'}), 1); assert.eq(coll.count({type: 'oak'}), 0); } }); commands.push({ req: { findAndModify: collName, query: {type: 'oak'}, update: [{$set: {type: 'ginkgo'}}], writeConcern: {w: 'majority'} }, setupFunc: function() { coll.insert({type: 'oak'}); assert.eq(coll.count({type: 'ginkgo'}), 0); assert.eq(coll.count({type: 'oak'}), 1); }, confirmFunc: function() { assert.eq(coll.count({type: 'ginkgo'}), 1); assert.eq(coll.count({type: 'oak'}), 0); } }); commands.push({ req: {applyOps: [{op: "u", ns: coll.getFullName(), o: {_id: 1, type: "willow"}, o2: {_id: 1}}]}, setupFunc: function() { coll.insert({_id: 1, type: 'oak'}); assert.eq(coll.count({type: 'willow'}), 0); }, confirmFunc: function() { assert.eq(coll.count({type: 'willow'}), 1); } }); commands.push({ req: {aggregate: collName, pipeline: [{$sort: {type: 1}}, {$out: "foo"}], cursor: {}}, setupFunc: function() { coll.insert({_id: 1, type: 'oak'}); coll.insert({_id: 2, type: 'maple'}); }, confirmFunc: function() { assert.eq(db.foo.count({type: 'oak'}), 1); assert.eq(db.foo.count({type: 'maple'}), 1); db.foo.drop(); } }); commands.push({ req: { mapReduce: collName, map: function() { this.tags.forEach(function(z) { emit(z, 1); }); }, reduce: function(key, values) { return {count: values.length}; }, out: "foo" }, setupFunc: function() { coll.insert({x: 1, tags: ["a", "b"]}); coll.insert({x: 2, tags: ["b", "c"]}); coll.insert({x: 3, tags: ["c", "a"]}); coll.insert({x: 4, tags: ["b", "c"]}); }, confirmFunc: function() { assert.eq(db.foo.findOne({_id: 'a'}).value.count, 2); assert.eq(db.foo.findOne({_id: 'b'}).value.count, 3); assert.eq(db.foo.findOne({_id: 'c'}).value.count, 3); db.foo.drop(); } }); function testValidWriteConcern(cmd) { cmd.req.writeConcern = {w: 'majority', wtimeout: ReplSetTest.kDefaultTimeoutMS}; jsTest.log("Testing " + tojson(cmd.req)); dropTestCollection(); cmd.setupFunc(); var res = db.runCommand(cmd.req); assert.commandWorked(res); assert(!res.writeConcernError, 'command on a full replicaset had writeConcernError: ' + tojson(res)); cmd.confirmFunc(); } function testInvalidWriteConcern(cmd) { cmd.req.writeConcern = {w: 'invalid'}; jsTest.log("Testing " + tojson(cmd.req)); dropTestCollection(); cmd.setupFunc(); var res = coll.runCommand(cmd.req); assert.commandFailedWithCode(res, ErrorCodes.UnknownReplWriteConcern); cmd.confirmFunc(); } commands.forEach(function(cmd) { testValidWriteConcern(cmd); testInvalidWriteConcern(cmd); }); replTest.stopSet(); })();