summaryrefslogtreecommitdiff
path: root/jstests/replsets/last_vote.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/replsets/last_vote.js')
-rw-r--r--jstests/replsets/last_vote.js397
1 files changed, 194 insertions, 203 deletions
diff --git a/jstests/replsets/last_vote.js b/jstests/replsets/last_vote.js
index 6ff7198b3d3..62901259364 100644
--- a/jstests/replsets/last_vote.js
+++ b/jstests/replsets/last_vote.js
@@ -11,216 +11,207 @@
// @tags: [requires_persistence]
(function() {
- "use strict";
- load("jstests/replsets/rslib.js"); // For getLatestOp()
-
- var name = "last_vote";
- var rst = new ReplSetTest({
- name: name,
- nodes: 2,
- });
- rst.startSet();
-
- // Lower the election timeout to make the test run faster since it waits for multiple elections.
- var conf = rst.getReplSetConfig();
- conf.settings = {
- electionTimeoutMillis: 6000,
- };
- rst.initiate(conf);
-
- const lastVoteNS = 'local.replset.election';
-
- function getLastVoteDoc(conn) {
- assert.eq(
- conn.getCollection(lastVoteNS).find().itcount(), 1, 'last vote should be singleton');
- return conn.getCollection(lastVoteNS).findOne();
+"use strict";
+load("jstests/replsets/rslib.js"); // For getLatestOp()
+
+var name = "last_vote";
+var rst = new ReplSetTest({
+ name: name,
+ nodes: 2,
+});
+rst.startSet();
+
+// Lower the election timeout to make the test run faster since it waits for multiple elections.
+var conf = rst.getReplSetConfig();
+conf.settings = {
+ electionTimeoutMillis: 6000,
+};
+rst.initiate(conf);
+
+const lastVoteNS = 'local.replset.election';
+
+function getLastVoteDoc(conn) {
+ assert.eq(conn.getCollection(lastVoteNS).find().itcount(), 1, 'last vote should be singleton');
+ return conn.getCollection(lastVoteNS).findOne();
+}
+
+function setLastVoteDoc(conn, term, candidate) {
+ var newLastVote = {term: term, candidateIndex: rst.getNodeId(candidate)};
+ return assert.writeOK(conn.getCollection(lastVoteNS).update({}, newLastVote));
+}
+
+function assertNodeHasLastVote(node, term, candidate) {
+ var lastVoteDoc = getLastVoteDoc(node);
+ assert.eq(lastVoteDoc.term, term, node.host + " had wrong last vote term.");
+ assert.eq(lastVoteDoc.candidateIndex,
+ rst.getNodeId(candidate),
+ node.host + " had wrong last vote candidate.");
+}
+
+function assertCurrentTerm(node, term) {
+ var stat = assert.commandWorked(node.adminCommand({replSetGetStatus: 1}));
+ assert.eq(stat.term, term, "Term changed when it should not have");
+}
+
+jsTestLog("Test that last vote is set on successive elections");
+
+// Run a few successive elections, alternating who becomes primary.
+var numElections = 3;
+for (var i = 0; i < numElections; i++) {
+ var primary = rst.getPrimary();
+ var secondary = rst.getSecondary();
+ var term = getLatestOp(primary).t;
+
+ // SERVER-20844 ReplSetTest starts up a single node replica set then reconfigures to the
+ // correct size, so secondaries didn't vote in the first election.
+ if (i > 0) {
+ jsTestLog("Last vote should have term: " + term + " and candidate: " + primary.host +
+ ", index: " + rst.getNodeId(primary));
+ rst.nodes.forEach(function(node) {
+ assertNodeHasLastVote(node, term, primary);
+ });
}
+ assert.commandWorked(primary.adminCommand({replSetStepDown: 60 * 10, force: true}));
- function setLastVoteDoc(conn, term, candidate) {
- var newLastVote = {term: term, candidateIndex: rst.getNodeId(candidate)};
- return assert.writeOK(conn.getCollection(lastVoteNS).update({}, newLastVote));
- }
+ // Make sure a new primary has been established.
+ rst.waitForState(primary, ReplSetTest.State.SECONDARY);
+ rst.waitForState(secondary, ReplSetTest.State.PRIMARY);
- function assertNodeHasLastVote(node, term, candidate) {
- var lastVoteDoc = getLastVoteDoc(node);
- assert.eq(lastVoteDoc.term, term, node.host + " had wrong last vote term.");
- assert.eq(lastVoteDoc.candidateIndex,
- rst.getNodeId(candidate),
- node.host + " had wrong last vote candidate.");
- }
+ // Reset election timeout for the old primary.
+ assert.commandWorked(primary.adminCommand({replSetFreeze: 0}));
+}
- function assertCurrentTerm(node, term) {
- var stat = assert.commandWorked(node.adminCommand({replSetGetStatus: 1}));
- assert.eq(stat.term, term, "Term changed when it should not have");
- }
+var term = getLatestOp(rst.getPrimary()).t + 100;
- jsTestLog("Test that last vote is set on successive elections");
-
- // Run a few successive elections, alternating who becomes primary.
- var numElections = 3;
- for (var i = 0; i < numElections; i++) {
- var primary = rst.getPrimary();
- var secondary = rst.getSecondary();
- var term = getLatestOp(primary).t;
-
- // SERVER-20844 ReplSetTest starts up a single node replica set then reconfigures to the
- // correct size, so secondaries didn't vote in the first election.
- if (i > 0) {
- jsTestLog("Last vote should have term: " + term + " and candidate: " + primary.host +
- ", index: " + rst.getNodeId(primary));
- rst.nodes.forEach(function(node) {
- assertNodeHasLastVote(node, term, primary);
- });
- }
- assert.commandWorked(primary.adminCommand({replSetStepDown: 60 * 10, force: true}));
-
- // Make sure a new primary has been established.
- rst.waitForState(primary, ReplSetTest.State.SECONDARY);
- rst.waitForState(secondary, ReplSetTest.State.PRIMARY);
-
- // Reset election timeout for the old primary.
- assert.commandWorked(primary.adminCommand({replSetFreeze: 0}));
- }
+jsTestLog("Test that last vote is loaded on startup");
- var term = getLatestOp(rst.getPrimary()).t + 100;
-
- jsTestLog("Test that last vote is loaded on startup");
-
- // Ensure that all ops are replicated before stepping up node 1.
- rst.awaitReplication();
-
- // We cannot reconfig node 0 to have priority 0 if it is currently the primary,
- // so we make sure node 1 is primary.
- jsTestLog("Stepping up node 1");
- rst.stepUp(rst.nodes[1]);
-
- jsTestLog("Reconfiguring cluster to make node 0 unelectable so it stays SECONDARY on restart");
- conf = rst.getReplSetConfigFromNode();
- conf.version++;
- conf.members[0].priority = 0;
- reconfig(rst, conf);
- rst.awaitNodesAgreeOnConfigVersion();
-
- jsTestLog("Restarting node 0 as a standalone");
- var node0 = rst.restart(0, {noReplSet: true}); // Restart as a standalone node.
- jsTestLog("Stopping node 1");
- rst.stop(1); // Stop node 1 so that node 0 controls the term by itself.
- jsTestLog("Setting the lastVote on node 0 to term: " + term + " candidate: " +
- rst.nodes[0].host + ", index: 0");
- setLastVoteDoc(node0, term, rst.nodes[0]);
-
- jsTestLog("Restarting node 0 in replica set mode");
- node0 = rst.restart(0); // Restart in replSet mode again.
- rst.waitForState(node0, ReplSetTest.State.SECONDARY);
-
- assert.soonNoExcept(function() {
- assertCurrentTerm(node0, term);
- return true;
- });
-
- jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command, " +
- "expecting failure in old term");
- var response = assert.commandWorked(node0.adminCommand({
- replSetRequestVotes: 1,
- setName: name,
- dryRun: true,
- term: term - 1,
- candidateIndex: 1,
- configVersion: conf.version,
- lastCommittedOp: getLatestOp(node0)
- }));
- assert.eq(response.term,
- term,
- "replSetRequestVotes response had the wrong term: " + tojson(response));
- assert(!response.voteGranted,
- "node granted vote in term before last vote doc: " + tojson(response));
- assertNodeHasLastVote(node0, term, rst.nodes[0]);
- assertCurrentTerm(node0, term);
+// Ensure that all ops are replicated before stepping up node 1.
+rst.awaitReplication();
- jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command in same term, " +
- "expecting success but no recording of lastVote");
- response = assert.commandWorked(node0.adminCommand({
- replSetRequestVotes: 1,
- setName: name,
- dryRun: true,
- term: term,
- candidateIndex: 1,
- configVersion: conf.version,
- lastCommittedOp: getLatestOp(node0)
- }));
- assert.eq(response.term,
- term,
- "replSetRequestVotes response had the wrong term: " + tojson(response));
- assert(response.voteGranted,
- "node failed to grant dryRun vote in term equal to last vote doc: " + tojson(response));
- assert.eq(response.reason,
- "",
- "replSetRequestVotes response had the wrong reason: " + tojson(response));
- assertNodeHasLastVote(node0, term, rst.nodes[0]);
- assertCurrentTerm(node0, term);
+// We cannot reconfig node 0 to have priority 0 if it is currently the primary,
+// so we make sure node 1 is primary.
+jsTestLog("Stepping up node 1");
+rst.stepUp(rst.nodes[1]);
- jsTestLog(
- "Manually sending node 0 a replSetRequestVotes command, expecting failure in same term");
- response = assert.commandWorked(node0.adminCommand({
- replSetRequestVotes: 1,
- setName: name,
- dryRun: false,
- term: term,
- candidateIndex: 1,
- configVersion: conf.version,
- lastCommittedOp: getLatestOp(node0)
- }));
- assert.eq(response.term,
- term,
- "replSetRequestVotes response had the wrong term: " + tojson(response));
- assert(!response.voteGranted,
- "node granted vote in term of last vote doc: " + tojson(response));
- assertNodeHasLastVote(node0, term, rst.nodes[0]);
- assertCurrentTerm(node0, term);
+jsTestLog("Reconfiguring cluster to make node 0 unelectable so it stays SECONDARY on restart");
+conf = rst.getReplSetConfigFromNode();
+conf.version++;
+conf.members[0].priority = 0;
+reconfig(rst, conf);
+rst.awaitNodesAgreeOnConfigVersion();
+
+jsTestLog("Restarting node 0 as a standalone");
+var node0 = rst.restart(0, {noReplSet: true}); // Restart as a standalone node.
+jsTestLog("Stopping node 1");
+rst.stop(1); // Stop node 1 so that node 0 controls the term by itself.
+jsTestLog("Setting the lastVote on node 0 to term: " + term + " candidate: " + rst.nodes[0].host +
+ ", index: 0");
+setLastVoteDoc(node0, term, rst.nodes[0]);
- jsTestLog("Manually sending node 0 a replSetRequestVotes command, " +
- "expecting success with a recording of the new lastVote");
- response = assert.commandWorked(node0.adminCommand({
- replSetRequestVotes: 1,
- setName: name,
- dryRun: false,
- term: term + 1,
- candidateIndex: 1,
- configVersion: conf.version,
- lastCommittedOp: getLatestOp(node0)
- }));
- assert.eq(response.term,
- term + 1,
- "replSetRequestVotes response had the wrong term: " + tojson(response));
- assert(response.voteGranted,
- "node failed to grant vote in term greater than last vote doc: " + tojson(response));
- assert.eq(response.reason,
- "",
- "replSetRequestVotes response had the wrong reason: " + tojson(response));
- assertNodeHasLastVote(node0, term + 1, rst.nodes[1]);
- assertCurrentTerm(node0, term + 1);
-
- jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command in future term, " +
- "expecting success but no recording of lastVote");
- response = assert.commandWorked(node0.adminCommand({
- replSetRequestVotes: 1,
- setName: name,
- dryRun: true,
- term: term + 2,
- candidateIndex: 1,
- configVersion: conf.version,
- lastCommittedOp: getLatestOp(node0)
- }));
- assert.eq(response.term,
- term + 2,
- "replSetRequestVotes response had the wrong term: " + tojson(response));
- assert(response.voteGranted,
- "node failed to grant vote in term greater than last vote doc: " + tojson(response));
- assert.eq(response.reason,
- "",
- "replSetRequestVotes response had the wrong reason: " + tojson(response));
- assertNodeHasLastVote(node0, term + 1, rst.nodes[1]);
- assertCurrentTerm(node0, term + 2);
-
- rst.stopSet();
+jsTestLog("Restarting node 0 in replica set mode");
+node0 = rst.restart(0); // Restart in replSet mode again.
+rst.waitForState(node0, ReplSetTest.State.SECONDARY);
+
+assert.soonNoExcept(function() {
+ assertCurrentTerm(node0, term);
+ return true;
+});
+
+jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command, " +
+ "expecting failure in old term");
+var response = assert.commandWorked(node0.adminCommand({
+ replSetRequestVotes: 1,
+ setName: name,
+ dryRun: true,
+ term: term - 1,
+ candidateIndex: 1,
+ configVersion: conf.version,
+ lastCommittedOp: getLatestOp(node0)
+}));
+assert.eq(
+ response.term, term, "replSetRequestVotes response had the wrong term: " + tojson(response));
+assert(!response.voteGranted,
+ "node granted vote in term before last vote doc: " + tojson(response));
+assertNodeHasLastVote(node0, term, rst.nodes[0]);
+assertCurrentTerm(node0, term);
+
+jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command in same term, " +
+ "expecting success but no recording of lastVote");
+response = assert.commandWorked(node0.adminCommand({
+ replSetRequestVotes: 1,
+ setName: name,
+ dryRun: true,
+ term: term,
+ candidateIndex: 1,
+ configVersion: conf.version,
+ lastCommittedOp: getLatestOp(node0)
+}));
+assert.eq(
+ response.term, term, "replSetRequestVotes response had the wrong term: " + tojson(response));
+assert(response.voteGranted,
+ "node failed to grant dryRun vote in term equal to last vote doc: " + tojson(response));
+assert.eq(
+ response.reason, "", "replSetRequestVotes response had the wrong reason: " + tojson(response));
+assertNodeHasLastVote(node0, term, rst.nodes[0]);
+assertCurrentTerm(node0, term);
+
+jsTestLog("Manually sending node 0 a replSetRequestVotes command, expecting failure in same term");
+response = assert.commandWorked(node0.adminCommand({
+ replSetRequestVotes: 1,
+ setName: name,
+ dryRun: false,
+ term: term,
+ candidateIndex: 1,
+ configVersion: conf.version,
+ lastCommittedOp: getLatestOp(node0)
+}));
+assert.eq(
+ response.term, term, "replSetRequestVotes response had the wrong term: " + tojson(response));
+assert(!response.voteGranted, "node granted vote in term of last vote doc: " + tojson(response));
+assertNodeHasLastVote(node0, term, rst.nodes[0]);
+assertCurrentTerm(node0, term);
+
+jsTestLog("Manually sending node 0 a replSetRequestVotes command, " +
+ "expecting success with a recording of the new lastVote");
+response = assert.commandWorked(node0.adminCommand({
+ replSetRequestVotes: 1,
+ setName: name,
+ dryRun: false,
+ term: term + 1,
+ candidateIndex: 1,
+ configVersion: conf.version,
+ lastCommittedOp: getLatestOp(node0)
+}));
+assert.eq(response.term,
+ term + 1,
+ "replSetRequestVotes response had the wrong term: " + tojson(response));
+assert(response.voteGranted,
+ "node failed to grant vote in term greater than last vote doc: " + tojson(response));
+assert.eq(
+ response.reason, "", "replSetRequestVotes response had the wrong reason: " + tojson(response));
+assertNodeHasLastVote(node0, term + 1, rst.nodes[1]);
+assertCurrentTerm(node0, term + 1);
+
+jsTestLog("Manually sending node 0 a dryRun replSetRequestVotes command in future term, " +
+ "expecting success but no recording of lastVote");
+response = assert.commandWorked(node0.adminCommand({
+ replSetRequestVotes: 1,
+ setName: name,
+ dryRun: true,
+ term: term + 2,
+ candidateIndex: 1,
+ configVersion: conf.version,
+ lastCommittedOp: getLatestOp(node0)
+}));
+assert.eq(response.term,
+ term + 2,
+ "replSetRequestVotes response had the wrong term: " + tojson(response));
+assert(response.voteGranted,
+ "node failed to grant vote in term greater than last vote doc: " + tojson(response));
+assert.eq(
+ response.reason, "", "replSetRequestVotes response had the wrong reason: " + tojson(response));
+assertNodeHasLastVote(node0, term + 1, rst.nodes[1]);
+assertCurrentTerm(node0, term + 2);
+
+rst.stopSet();
})();