jstests/replsets/libs/election_handoff.js
/**
     * Exercises and validates an election handoff scenario by stepping down the primary and
     * ensuring that the node at "expectedCandidateId" is stepped up in its place. The desired
     * configuration of the replica set is passed in as its ReplSetTest instance.
     *
     * The options parameter contains extra options for the handoff.  Currently supported options
     * are:
     *   stepDownBySignal - When this option is set, the primary will be stepped down by stopping
     *                      and restarting with sigterm, rather than with a replSetStepDown command
     *   stepDownPeriodSecs - The number of seconds to step down the primary.
     *   secondaryCatchUpPeriodSecs - The number of seconds that the mongod will wait for an
     *                                electable secondary to catch up to the primary.
     */
Exercises and validates an election handoff scenario by stepping down the primary and
ensuring that the node at "expectedCandidateId" is stepped up in its place. The desired
configuration of the replica set is passed in as its ReplSetTest instance.

The options parameter contains extra options for the handoff.  Currently supported options
are:
stepDownBySignal - When this option is set, the primary will be stepped down by stopping
and restarting with sigterm, rather than with a replSetStepDown command
stepDownPeriodSecs - The number of seconds to step down the primary.
secondaryCatchUpPeriodSecs - The number of seconds that the mongod will wait for an
electable secondary to catch up to the primary.
Exercises and validates an election handoff scenario by stepping down the primary and ensuring that the node at " expectedCandidateId " is stepped up in its place . The desired configuration of the replica set is passed in as its ReplSetTest instance . The options parameter contains extra options for the handoff . Currently supported options are : stepDownBySignal - When this option is set the primary will be stepped down by stopping and restarting with sigterm rather than with a replSetStepDown command stepDownPeriodSecs - The number of seconds to step down the primary . secondaryCatchUpPeriodSecs - The number of seconds that the mongod will wait for an electable secondary to catch up to the primary .
function testElectionHandoff(rst, initialPrimaryId, expectedCandidateId, options = {}) {
        const config = rst.getReplSetConfigFromNode();
        const numNodes = config.members.length;
        const memberInfo = config.members[expectedCandidateId];
        assert.neq(
            true, memberInfo["arbiterOnly"], "Election handoff candidate cannot be an arbiter.");
        assert.neq(
            0, memberInfo["priority"], "Election handoff candidate cannot have zero priority");
        rst.awaitNodesAgreeOnPrimary();
        const primary = rst.getPrimary();
        assert.eq(rst.nodes[initialPrimaryId], primary);
        const status = assert.commandWorked(primary.adminCommand({replSetGetStatus: 1}));
        const term = +status.term;
        jsTestLog("Enabling election handoff...");
        assert.commandWorked(primary.adminCommand({setParameter: 1, enableElectionHandoff: 1}));
        jsTestLog("Stepping down primary...");
        assert.commandWorked(primary.getDB("test").secondariesMustBeCaughtUpToHere.insert(
            {"a": 1}, {writeConcern: {w: rst.nodes.length}}));
        rst.awaitNodesAgreeOnAppliedOpTime();
        if (options["stepDownBySignal"]) {
            rst.stop(initialPrimaryId, kSIGTERM, {skipValidation: true}, {forRestart: true});
            rst.start(initialPrimaryId, {}, true);
        } else {
            assert.commandWorked(primary.adminCommand({
                replSetStepDown: options.stepDownPeriodSecs || kStepDownPeriodSecs,
                secondaryCatchUpPeriodSecs:
                    options.secondaryCatchUpPeriodSecs || kStepDownPeriodSecs / 2
            }));
        }
        jsTestLog(`Checking that the secondary with id ${expectedCandidateId} is stepped up...`);
        const expectedCandidate = rst.nodes[expectedCandidateId];
        checkLog.contains(expectedCandidate, "Starting an election due to step up request");
        if (isJsonLog(expectedCandidate)) {
            if (numNodes === 2) {
                checkLog.contains(
                    expectedCandidate,
                    `Skipping dry run and running for election","attr":{"newTerm":${term + 1}}}`);
                checkLog.checkContainsOnceJson(
                    expectedCandidate,
                    51799,
                    {"term": term + 1, vote: "yes", "from": primary.host});
            }
        } else {
            if (numNodes === 2) {
                checkLog.contains(expectedCandidate,
                                  `skipping dry run and running for election in term ${term + 1}`);
                checkLog.contains(
                    expectedCandidate,
                    `VoteRequester(term ${term + 1}) received a yes vote from ${primary.host}`);
            }
        }
        rst.awaitNodesAgreeOnPrimary();
        assert.eq(rst.nodes[expectedCandidateId], rst.getPrimary());
    }
function testElectionHandoff ( rst , initialPrimaryId , expectedCandidateId , options = { } ) { const config = rst . getReplSetConfigFromNode ( ) ; const numNodes = config . members . length ; const memberInfo = config . members [ expectedCandidateId ] ; assert . neq ( true , memberInfo [ "arbiterOnly" ] , "Election handoff candidate cannot be an arbiter." ) ; assert . neq ( 0 , memberInfo [ "priority" ] , "Election handoff candidate cannot have zero priority" ) ; rst . awaitNodesAgreeOnPrimary ( ) ; const primary = rst . getPrimary ( ) ; assert . eq ( rst . nodes [ initialPrimaryId ] , primary ) ; const status = assert . commandWorked ( primary . adminCommand ( { replSetGetStatus : 1 } ) ) ; const term = + status . term ; jsTestLog ( "Enabling election handoff..." ) ; assert . commandWorked ( primary . adminCommand ( { setParameter : 1 , enableElectionHandoff : 1 } ) ) ; jsTestLog ( "Stepping down primary..." ) ; assert . commandWorked ( primary . getDB ( "test" ) . secondariesMustBeCaughtUpToHere . insert ( { "a" : 1 } , { writeConcern : { w : rst . nodes . length } } ) ) ; rst . awaitNodesAgreeOnAppliedOpTime ( ) ; if ( options [ "stepDownBySignal" ] ) { rst . stop ( initialPrimaryId , kSIGTERM , { skipValidation : true } , { forRestart : true } ) ; rst . start ( initialPrimaryId , { } , true ) ; } else { assert . commandWorked ( primary . adminCommand ( { replSetStepDown : options . stepDownPeriodSecs || kStepDownPeriodSecs , secondaryCatchUpPeriodSecs : options . secondaryCatchUpPeriodSecs || kStepDownPeriodSecs / 2 } ) ) ; } jsTestLog ( ` ${ expectedCandidateId } ` ) ; const expectedCandidate = rst . nodes [ expectedCandidateId ] ; checkLog . contains ( expectedCandidate , "Starting an election due to step up request" ) ; if ( isJsonLog ( expectedCandidate ) ) { if ( numNodes === 2 ) { checkLog . contains ( expectedCandidate , ` ${ term + 1 } ` ) ; checkLog . checkContainsOnceJson ( expectedCandidate , 51799 , { "term" : term + 1 , vote : "yes" , "from" : primary . host } ) ; } } else { if ( numNodes === 2 ) { checkLog . contains ( expectedCandidate , ` ${ term + 1 } ` ) ; checkLog . contains ( expectedCandidate , ` ${ term + 1 } ${ primary . host } ` ) ; } } rst . awaitNodesAgreeOnPrimary ( ) ; assert . eq ( rst . nodes [ expectedCandidateId ] , rst . getPrimary ( ) ) ; }
Exercises and validates an election handoff scenario by stepping down the primary and
 ensuring that the node at "expectedCandidateId" is stepped up in its place.
Exercises and validates an election handoff scenario by stepping down the primary and ensuring that the node at " expectedCandidateId " is stepped up in its place .
// Store the term for future verification. // Election handoff is enabled by default. This test explicitly configures it for safety // purposes. // Make sure all secondaries are ready before stepping down. We must additionally // make sure that the primary is aware that the secondaries are ready and caught up // to the primary's lastApplied, so we issue a dummy write and wait on its optime. // Step down the current primary. Skip validation since it prevents election handoff. // The checkLog() function blocks until the log line appears. // If there are only two nodes in the set, verify that the old primary voted "yes". // If there are only two nodes in the set, verify that the old primary voted "yes".