/** * This test checks that the 'newTermStartDate' and 'newTermAppliedDate' metrics in * 'electionParticipantMetrics' are set and updated correctly. We test this with a three node * replica set by successfully stepping up one of the secondaries, then failing to step up the * original primary. We check that the metrics are appropriately set or unset after each election. */ (function() { "use strict"; const testName = jsTestName(); const rst = ReplSetTest({name: testName, nodes: [{}, {}, {rsConfig: {priority: 0}}]}); rst.startSet(); // Make sure there are no election timeouts firing for the duration of the test. This helps // ensure that the test will only pass if the election succeeds. rst.initiateWithHighElectionTimeout(); const originalPrimary = rst.getPrimary(); const newPrimary = rst.getSecondaries()[0]; const testNode = rst.getSecondaries()[1]; // Set up a failpoint that forces the original primary to vote no in this election. This guarantees // that 'testNode' will be a participant in this election, since its vote will be needed for the new // primary to win. assert.commandWorked( originalPrimary.adminCommand({configureFailPoint: "voteNoInElection", mode: "alwaysOn"})); // Step up the new primary. assert.commandWorked(newPrimary.adminCommand({replSetStepUp: 1})); rst.awaitNodesAgreeOnPrimary(); assert.eq(newPrimary, rst.getPrimary()); // Since the new term oplog entry needs to be replicated onto testNode for the metrics to be set, we // must await replication before checking the metrics. rst.awaitReplication(); let testNodeReplSetGetStatus = assert.commandWorked(testNode.adminCommand({replSetGetStatus: 1})); let testNodeElectionParticipantMetrics = testNodeReplSetGetStatus.electionParticipantMetrics; const originalNewTermStartDate = testNodeElectionParticipantMetrics.newTermStartDate; const originalNewTermAppliedDate = testNodeElectionParticipantMetrics.newTermAppliedDate; // These fields should be set, since testNode has received and applied the new term oplog entry // after the election. assert(originalNewTermStartDate, () => "Response should have an 'electionParticipantMetrics.newTermStartDate' field: " + tojson(testNodeElectionParticipantMetrics)); assert(originalNewTermAppliedDate, () => "Response should have an 'electionParticipantMetrics.newTermAppliedDate' field: " + tojson(testNodeElectionParticipantMetrics)); // Set up a failpoint that forces newPrimary and testNode to vote no in the election, in addition to // the new primary above. This will cause the dry run to fail for the original primary. assert.commandWorked( newPrimary.adminCommand({configureFailPoint: "voteNoInElection", mode: "alwaysOn"})); assert.commandWorked( testNode.adminCommand({configureFailPoint: "voteNoInElection", mode: "alwaysOn"})); // Attempt to step up the original primary. assert.commandFailedWithCode(originalPrimary.adminCommand({replSetStepUp: 1}), ErrorCodes.CommandFailed); testNodeReplSetGetStatus = assert.commandWorked(testNode.adminCommand({replSetGetStatus: 1})); testNodeElectionParticipantMetrics = testNodeReplSetGetStatus.electionParticipantMetrics; // The 'newTermStartDate' and 'newTermAppliedDate' fields should not be cleared, since the term is // not incremented when a dry run election is initiated. assert(testNodeElectionParticipantMetrics.newTermStartDate, () => "Response should have an 'electionParticipantMetrics.newTermStartDate' field: " + tojson(testNodeElectionParticipantMetrics)); assert(testNodeElectionParticipantMetrics.newTermAppliedDate, () => "Response should have an 'electionParticipantMetrics.newTermAppliedDate' field: " + tojson(testNodeElectionParticipantMetrics)); // The fields should store the same dates, since a new term oplog entry was not received. assert.eq(originalNewTermStartDate, testNodeElectionParticipantMetrics.newTermStartDate); assert.eq(originalNewTermAppliedDate, testNodeElectionParticipantMetrics.newTermAppliedDate); // Clear the previous failpoint and set up a new one that forces the two current secondaries to vote // yes for the candidate in the dry run election and no in the real election. This will cause the // real election to fail. assert.commandWorked( newPrimary.adminCommand({configureFailPoint: "voteNoInElection", mode: "off"})); assert.commandWorked(newPrimary.adminCommand( {configureFailPoint: "voteYesInDryRunButNoInRealElection", mode: "alwaysOn"})); assert.commandWorked(testNode.adminCommand({configureFailPoint: "voteNoInElection", mode: "off"})); assert.commandWorked(testNode.adminCommand( {configureFailPoint: "voteYesInDryRunButNoInRealElection", mode: "alwaysOn"})); // Attempt to step up the original primary. assert.commandFailedWithCode(originalPrimary.adminCommand({replSetStepUp: 1}), ErrorCodes.CommandFailed); testNodeReplSetGetStatus = assert.commandWorked(testNode.adminCommand({replSetGetStatus: 1})); testNodeElectionParticipantMetrics = testNodeReplSetGetStatus.electionParticipantMetrics; // Since the election succeeded in the dry run, a new term was encountered by the secondary. // However, because the real election failed, there was no new term oplog entry, so these fields // should not be set. assert(!testNodeElectionParticipantMetrics.newTermStartDate, () => "Response should not have an 'electionParticipantMetrics.newTermStartDate' field: " + tojson(testNodeElectionParticipantMetrics)); assert(!testNodeElectionParticipantMetrics.newTermAppliedDate, () => "Response should not have an 'electionParticipantMetrics.newTermAppliedDate' field: " + tojson(testNodeElectionParticipantMetrics)); rst.stopSet(); })();