From af654fa43fe293f9c3551ac50e908fcc618ca875 Mon Sep 17 00:00:00 2001 From: Esha Maharishi Date: Wed, 7 Sep 2016 18:41:36 -0400 Subject: SERVER-26008 allow setting failpoints on the command line --- jstests/fail_point/fail_point.js | 56 +++++---- .../set_failpoint_through_set_parameter.js | 139 +++++++++++++++++++++ 2 files changed, 171 insertions(+), 24 deletions(-) create mode 100644 jstests/fail_point/set_failpoint_through_set_parameter.js (limited to 'jstests') diff --git a/jstests/fail_point/fail_point.js b/jstests/fail_point/fail_point.js index ccf5ac4c16f..0bb08f0b358 100644 --- a/jstests/fail_point/fail_point.js +++ b/jstests/fail_point/fail_point.js @@ -1,33 +1,25 @@ /** - * Performs basic checks on the failpoint command. Also check + * Performs basic checks on the configureFailPoint command. Also check * mongo/util/fail_point_test.cpp for unit tests. * * @param adminDB {DB} the admin database database object */ var runTest = function(adminDB) { - /** - * Checks whether the result object from the configureFailPoint command - * matches what we expect. - * - * @param resultObj {Object} - * @param expectedMode {Number} - * @param expectedData {Object} - */ - var expectedFPState = function(resultObj, expectedMode, expectedData) { - assert(resultObj.ok); - assert.eq(expectedMode, resultObj.mode); + var expectFailPointState = function(fpState, expectedMode, expectedData) { + assert.eq(expectedMode, fpState.mode); - // Valid only for 1 level field checks - for (var field in expectedData) { - assert.eq(expectedData[field], resultObj.data[field]); + // Check that all expected data is present. + for (var field in expectedData) { // Valid only for 1 level field checks + assert.eq(expectedData[field], fpState.data[field]); } - for (field in resultObj.data) { - assert.eq(expectedData[field], resultObj.data[field]); + // Check that all present data is expected. + for (field in fpState.data) { + assert.eq(expectedData[field], fpState.data[field]); } }; - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 0, {}); + // A failpoint's state can be read through getParameter by prefixing its name with "failpoint." // Test non-existing fail point assert.commandFailed( @@ -35,28 +27,44 @@ var runTest = function(adminDB) { // Test bad mode string assert.commandFailed( - adminDB.runCommand({configureFailPoint: 'dummy', mode: 'madMode', data: {x: 1}})); - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 0, {}); + adminDB.runCommand({configureFailPoint: 'dummy', mode: 'badMode', data: {x: 1}})); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 0, {}); // Test bad mode obj assert.commandFailed( adminDB.runCommand({configureFailPoint: 'dummy', mode: {foo: 3}, data: {x: 1}})); - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 0, {}); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 0, {}); // Test bad mode type assert.commandFailed( adminDB.runCommand({configureFailPoint: 'dummy', mode: true, data: {x: 1}})); - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 0, {}); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 0, {}); // Test bad data type assert.commandFailed( adminDB.runCommand({configureFailPoint: 'dummy', mode: 'alwaysOn', data: 'data'})); - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 0, {}); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 0, {}); + + // Test setting mode to off. + assert.commandWorked(adminDB.runCommand({configureFailPoint: 'dummy', mode: 'off'})); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 0, {}); // Test good command w/ data assert.commandWorked( adminDB.runCommand({configureFailPoint: 'dummy', mode: 'alwaysOn', data: {x: 1}})); - expectedFPState(adminDB.runCommand({configureFailPoint: 'dummy'}), 1, {x: 1}); + var res = adminDB.runCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.commandWorked(res); + expectFailPointState(res["failpoint.dummy"], 1, {x: 1}); }; var conn = MongoRunner.runMongod(); diff --git a/jstests/fail_point/set_failpoint_through_set_parameter.js b/jstests/fail_point/set_failpoint_through_set_parameter.js new file mode 100644 index 00000000000..3ba05f51582 --- /dev/null +++ b/jstests/fail_point/set_failpoint_through_set_parameter.js @@ -0,0 +1,139 @@ +/** + * Tests that failpoints can be set via --setParameter on the command line for mongos and mongod + * only when running with enableTestCommands=1. + */ +(function() { + + "use strict"; + + var assertStartupSucceeds = function(conn) { + assert.commandWorked(conn.adminCommand({ismaster: 1})); + }; + + var assertStartupFails = function(conn) { + assert.eq(null, conn); + }; + + var validFailpointPayload = {'mode': 'alwaysOn'}; + var validFailpointPayloadWithData = {'mode': 'alwaysOn', 'data': {x: 1}}; + var invalidFailpointPayload = "notJSON"; + + // In order to be able connect to a mongos that starts up successfully, start a config replica + // set so that we can provide a valid config connection string to the mongos. + var configRS = new ReplSetTest({nodes: 3}); + configRS.startSet({'configsvr': ''}); + configRS.initiate(); + + // Setting a failpoint via --setParameter fails if enableTestCommands is not on. + jsTest.setOption('enableTestCommands', false); + assertStartupFails( + MongoRunner.runMongod({setParameter: "failpoint.dummy=" + tojson(validFailpointPayload)})); + assertStartupFails(MongoRunner.runMongos({ + setParameter: "failpoint.dummy=" + tojson(validFailpointPayload), + configdb: configRS.getURL() + })); + jsTest.setOption('enableTestCommands', true); + + // Passing an invalid failpoint payload fails. + assertStartupFails(MongoRunner.runMongod( + {setParameter: "failpoint.dummy=" + tojson(invalidFailpointPayload)})); + assertStartupFails(MongoRunner.runMongos({ + setParameter: "failpoint.dummy=" + tojson(invalidFailpointPayload), + configdb: configRS.getURL() + })); + + // Valid startup configurations succeed. + var mongod = + MongoRunner.runMongod({setParameter: "failpoint.dummy=" + tojson(validFailpointPayload)}); + assertStartupSucceeds(mongod); + MongoRunner.stopMongod(mongod); + + var mongos = MongoRunner.runMongos({ + setParameter: "failpoint.dummy=" + tojson(validFailpointPayload), + configdb: configRS.getURL() + }); + assertStartupSucceeds(mongos); + MongoRunner.stopMongos(mongos); + + mongod = MongoRunner.runMongod( + {setParameter: "failpoint.dummy=" + tojson(validFailpointPayloadWithData)}); + assertStartupSucceeds(mongod); + + mongos = MongoRunner.runMongos({ + setParameter: "failpoint.dummy=" + tojson(validFailpointPayloadWithData), + configdb: configRS.getURL() + }); + assertStartupSucceeds(mongos); + + // The failpoint shows up with the correct data in the results of getParameter. + + var res = mongod.adminCommand({getParameter: "*"}); + assert.neq(null, res); + assert.neq(null, res["failpoint.dummy"]); + assert.eq(1, res["failpoint.dummy"].mode); // the 'mode' is an enum internally; 'alwaysOn' is 1 + assert.eq(validFailpointPayloadWithData.data, res["failpoint.dummy"].data); + + res = mongos.adminCommand({getParameter: "*"}); + assert.neq(null, res); + assert.neq(null, res["failpoint.dummy"]); + assert.eq(1, res["failpoint.dummy"].mode); // the 'mode' is an enum internally; 'alwaysOn' is 1 + assert.eq(validFailpointPayloadWithData.data, res["failpoint.dummy"].data); + + // The failpoint cannot be set by the setParameter command. + assert.commandFailed(mongod.adminCommand({setParameter: 1, "dummy": validFailpointPayload})); + assert.commandFailed(mongos.adminCommand({setParameter: 1, "dummy": validFailpointPayload})); + + // After changing the failpoint's state through the configureFailPoint command, the changes are + // reflected in the output of the getParameter command. + + var newData = {x: 2}; + + mongod.adminCommand({configureFailPoint: "dummy", mode: "alwaysOn", data: newData}); + res = mongod.adminCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.neq(null, res); + assert.neq(null, res["failpoint.dummy"]); + assert.eq(1, res["failpoint.dummy"].mode); // the 'mode' is an enum internally; 'alwaysOn' is 1 + assert.eq(newData, res["failpoint.dummy"].data); + + mongos.adminCommand({configureFailPoint: "dummy", mode: "alwaysOn", data: newData}); + res = mongos.adminCommand({getParameter: 1, "failpoint.dummy": 1}); + assert.neq(null, res); + assert.neq(null, res["failpoint.dummy"]); + assert.eq(1, res["failpoint.dummy"].mode); // the 'mode' is an enum internally; 'alwaysOn' is 1 + assert.eq(newData, res["failpoint.dummy"].data); + + MongoRunner.stopMongod(mongod); + MongoRunner.stopMongos(mongos); + + // Failpoint server parameters do not show up in the output of getParameter when not running + // with enableTestCommands=1. + + jsTest.setOption('enableTestCommands', false); + + mongod = MongoRunner.runMongod(); + assertStartupSucceeds(mongod); + + mongos = MongoRunner.runMongos({configdb: configRS.getURL()}); + assertStartupSucceeds(mongos); + + // Doing getParameter for a specific failpoint fails. + assert.commandFailed(mongod.adminCommand({getParameter: 1, "failpoint.dummy": 1})); + assert.commandFailed(mongos.adminCommand({getParameter: 1, "failpoint.dummy": 1})); + + // No failpoint parameters show up when listing all parameters through getParameter. + res = mongod.adminCommand({getParameter: "*"}); + assert.neq(null, res); + for (var parameter in res) { // for-in loop valid only for top-level field checks. + assert(!parameter.includes("failpoint.")); + } + + res = mongos.adminCommand({getParameter: "*"}); + assert.neq(null, res); + for (var parameter in res) { // for-in loop valid only for top-level field checks. + assert(!parameter.includes("failpoint.")); + } + + MongoRunner.stopMongod(mongod); + MongoRunner.stopMongos(mongos); + configRS.stopSet(); +})(); -- cgit v1.2.1