/* Tests the "failCommand" failpoint. * @tags: [assumes_read_concern_unchanged, assumes_read_preference_unchanged] */ (function() { "use strict"; const testDB = db.getSiblingDB("test_failcommand"); const adminDB = db.getSiblingDB("admin"); const getThreadName = function() { let myUri = adminDB.runCommand({whatsmyuri: 1}).you; return adminDB.aggregate([{$currentOp: {localOps: true}}, {$match: {client: myUri}}]) .toArray()[0] .desc; }; let threadName = getThreadName(); // Test failing with a particular error code. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: "alwaysOn", data: { errorCode: ErrorCodes.NotMaster, failCommands: ["ping"], threadName: threadName, } })); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.NotMaster); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test that only commands specified in failCommands fail. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: "alwaysOn", data: { errorCode: ErrorCodes.BadValue, failCommands: ["ping"], threadName: threadName, } })); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.BadValue); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({find: "collection"})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test failing with multiple commands specified in failCommands. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: "alwaysOn", data: { errorCode: ErrorCodes.BadValue, failCommands: ["ping", "isMaster"], threadName: threadName, } })); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.BadValue); assert.commandFailedWithCode(testDB.runCommand({isMaster: 1}), ErrorCodes.BadValue); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test skip when failing with a particular error code. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {skip: 2}, data: { errorCode: ErrorCodes.NotMaster, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.NotMaster); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test times when failing with a particular error code. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 2}, data: { errorCode: ErrorCodes.NotMaster, failCommands: ["ping"], threadName: threadName, } })); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.NotMaster); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.NotMaster); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Commands not specified in failCommands are not counted for skip. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {skip: 1}, data: { errorCode: ErrorCodes.BadValue, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(testDB.runCommand({find: "c"})); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.BadValue); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Commands not specified in failCommands are not counted for times. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { errorCode: ErrorCodes.BadValue, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({find: "c"})); assert.commandFailedWithCode(testDB.runCommand({ping: 1}), ErrorCodes.BadValue); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test closing connection. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: "alwaysOn", data: { closeConnection: true, failCommands: ["ping"], threadName: threadName, } })); assert.throws(() => testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); threadName = getThreadName(); // Test that only commands specified in failCommands fail when closing the connection. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: "alwaysOn", data: { closeConnection: true, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({find: "c"})); assert.throws(() => testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); threadName = getThreadName(); // Test skip when closing connection. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {skip: 2}, data: { closeConnection: true, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(testDB.runCommand({ping: 1})); assert.throws(() => testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); threadName = getThreadName(); // Commands not specified in failCommands are not counted for skip. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {skip: 1}, data: { closeConnection: true, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(testDB.runCommand({find: "c"})); assert.throws(() => testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); threadName = getThreadName(); // Commands not specified in failCommands are not counted for times. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { closeConnection: true, failCommands: ["ping"], threadName: threadName, } })); assert.commandWorked(testDB.runCommand({isMaster: 1})); assert.commandWorked(testDB.runCommand({buildinfo: 1})); assert.commandWorked(testDB.runCommand({find: "c"})); assert.throws(() => testDB.runCommand({ping: 1})); assert.commandWorked(testDB.runCommand({ping: 1})); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); threadName = getThreadName(); // Cannot fail on "configureFailPoint" command. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { errorCode: ErrorCodes.BadValue, failCommands: ["configureFailPoint"], threadName: threadName, } })); assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test with success and writeConcernError. assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { writeConcernError: {code: 12345, errmsg: "hello"}, failCommands: ['insert', 'ping'], threadName: threadName, } })); // Commands that don't support writeConcern don't tick counter. assert.commandWorked(testDB.runCommand({ping: 1})); // Unlisted commands don't tick counter. assert.commandWorked(testDB.runCommand({update: "c", updates: [{q: {}, u: {}, upsert: true}]})); var res = testDB.runCommand({insert: "c", documents: [{}]}); assert.commandWorkedIgnoringWriteConcernErrors(res); assert.eq(res.writeConcernError, {code: 12345, errmsg: "hello"}); assert.commandWorked(testDB.runCommand({insert: "c", documents: [{}]})); // Works again. assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test with natural failure and writeConcernError. // This document is removed before testing the following insert to prevent a DuplicateKeyError // if the failcommand_failpoint test is run multiple times on the same fixture. testDB.c.remove({_id: 'dup'}); assert.commandWorked(testDB.runCommand({insert: "c", documents: [{_id: 'dup'}]})); assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { writeConcernError: {code: 12345, errmsg: "hello"}, failCommands: ['insert'], threadName: threadName, } })); var res = testDB.runCommand({insert: "c", documents: [{_id: 'dup'}]}); assert.commandFailedWithCode(res, ErrorCodes.DuplicateKey); assert.eq(res.writeConcernError, {code: 12345, errmsg: "hello"}); assert.commandWorked(testDB.runCommand({insert: "c", documents: [{}]})); // Works again. assert.commandWorked(adminDB.runCommand({configureFailPoint: "failCommand", mode: "off"})); // Test that specifying both writeConcernError and closeConnection : false will not make // `times` decrement twice per operation assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 2}, data: { failCommands: ["insert"], closeConnection: false, writeConcernError: {code: 12345, errmsg: "hello"}, threadName: threadName, } })); var res = testDB.runCommand({insert: "test", documents: [{a: "something"}]}); assert.commandWorkedIgnoringWriteConcernErrors(res); assert.eq(res.writeConcernError, {code: 12345, errmsg: "hello"}); res = testDB.runCommand({insert: "test", documents: [{a: "something else"}]}); assert.commandWorkedIgnoringWriteConcernErrors(res); assert.eq(res.writeConcernError, {code: 12345, errmsg: "hello"}); assert.commandWorked(testDB.runCommand({insert: "test", documents: [{b: "or_other"}]})); // // Test that the namespace parameter is obeyed. // assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { errorCode: ErrorCodes.InternalError, failCommands: ["find"], namespace: testDB.getName() + ".foo", threadName: threadName, } })); // A find against a different namespace should not trigger the failpoint. assert.commandWorked(testDB.runCommand({find: "test"})); // A find against the namespace given to the failpoint should trigger the failpoint. assert.commandFailedWithCode(testDB.runCommand({find: "foo"}), ErrorCodes.InternalError); // // Test that the namespace parameter is obeyed for write concern errors. // assert.commandWorked(adminDB.runCommand({ configureFailPoint: "failCommand", mode: {times: 1}, data: { failCommands: ["insert"], namespace: testDB.getName() + ".foo", threadName: threadName, writeConcernError: {code: ErrorCodes.InternalError, errmsg: "foo"}, } })); // An insert to a different namespace should not trigger the failpoint. assert.commandWorked( testDB.runCommand({insert: "test", documents: [{x: "doc_for_namespace_no_wce"}]})); // An insert to the namespace given to the failpoint should trigger the failpoint. res = assert.commandWorkedIgnoringWriteConcernErrors(testDB.runCommand( {insert: "foo", documents: [{x: "doc_for_namespace_case_should_trigger_wce"}]})); assert.eq(res.writeConcernError, {code: ErrorCodes.InternalError, errmsg: "foo"}); }());