mirror of https://github.com/mongodb/mongo
377 lines
12 KiB
JavaScript
377 lines
12 KiB
JavaScript
/**
|
|
* Checks all the easily testable fields in the response object returned by the hello() command and
|
|
* its aliases, isMaster() and ismaster(). This test also checks that fields that should not be in
|
|
* the document are absent.
|
|
* @tags: [
|
|
* ]
|
|
*/
|
|
|
|
// Skip db hash check because node 2 is slave delayed and may time out on awaitReplication.
|
|
TestData.skipCheckDBHashes = true;
|
|
|
|
load("jstests/replsets/rslib.js");
|
|
|
|
// function create the error message if an assert fails
|
|
var generateErrorString = function(badFields, missingFields, badValues, result) {
|
|
var str = "\nThe result was:\n" + tojson(result);
|
|
if (badFields.length !== 0) {
|
|
str += "\nIt had the following fields which it shouldn't have: ";
|
|
str += badFields;
|
|
}
|
|
if (missingFields.length !== 0) {
|
|
str += "\nIt lacked the following fields which it should have contained: ";
|
|
str += missingFields;
|
|
}
|
|
if (badValues.length !== 0) {
|
|
for (i = 0; i < badValues.length; i += 3) {
|
|
str += "\nIts value for " + badValues[i] + " is " + badValues[i + 1];
|
|
str += " but should be " + badValues[i + 2];
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
// This function calls checkResponseFields with the isMaster and hello commands.
|
|
var runHelloCmdAndAliases = function(memberInfo) {
|
|
checkResponseFields(memberInfo, "ismaster");
|
|
checkResponseFields(memberInfo, "isMaster");
|
|
checkResponseFields(memberInfo, "hello");
|
|
};
|
|
|
|
// This function runs either the isMaster or hello command, and validates that the response is what
|
|
// we expect.
|
|
var checkResponseFields = function(memberInfo, cmd) {
|
|
// run the passed in command on the connection
|
|
var result = memberInfo.conn.getDB("admin").runCommand(cmd);
|
|
// If we are running the hello command, we must modify the expected fields. We expect
|
|
// "isWritablePrimary" and "secondaryDelaySecs" instead of "ismaster" and "slaveDelay" in the
|
|
// hello command response.
|
|
if (cmd === "hello") {
|
|
memberInfo.goodValues.isWritablePrimary = memberInfo.goodValues.ismaster;
|
|
delete memberInfo.goodValues.ismaster;
|
|
memberInfo.unwantedFields.push("ismaster");
|
|
memberInfo.unwantedFields =
|
|
memberInfo.unwantedFields.filter(f => f !== "isWritablePrimary");
|
|
|
|
if (memberInfo.goodValues.hasOwnProperty("slaveDelay")) {
|
|
memberInfo.goodValues.secondaryDelaySecs = memberInfo.goodValues.slaveDelay;
|
|
delete memberInfo.goodValues.slaveDelay;
|
|
memberInfo.unwantedFields.push("slaveDelay");
|
|
memberInfo.unwantedFields =
|
|
memberInfo.unwantedFields.filter(f => f !== "secondaryDelaySecs");
|
|
}
|
|
}
|
|
|
|
// make sure result doesn't contain anything it shouldn't
|
|
var badFields = [];
|
|
for (field in result) {
|
|
if (!result.hasOwnProperty(field)) {
|
|
continue;
|
|
}
|
|
if (Array.contains(memberInfo.unwantedFields, field)) {
|
|
badFields.push(field);
|
|
}
|
|
}
|
|
|
|
// make sure result contains the fields we want
|
|
var missingFields = [];
|
|
for (i = 0; i < memberInfo.wantedFields.length; i++) {
|
|
field = memberInfo.wantedFields[i];
|
|
if (!result.hasOwnProperty(field)) {
|
|
missingFields.push(field);
|
|
print(field);
|
|
}
|
|
}
|
|
|
|
// make sure the result has proper values for fields with known values
|
|
var badValues = []; // each mistake will be saved as three entries (key, badvalue, goodvalue)
|
|
for (field in memberInfo.goodValues) {
|
|
if (typeof (memberInfo.goodValues[field]) === "object") {
|
|
// assumes nested obj is disk in tags this is currently true, but may change
|
|
if (result[field].disk !== memberInfo.goodValues[field].disk) {
|
|
badValues.push("tags.disk");
|
|
badValues.push(result[field].disk);
|
|
badValues.push(memberInfo.goodValues[field].disk);
|
|
}
|
|
} else {
|
|
if (result[field] !== memberInfo.goodValues[field]) {
|
|
badValues.push(field);
|
|
badValues.push(result[field]);
|
|
badValues.push(memberInfo.goodValues[field]);
|
|
}
|
|
}
|
|
}
|
|
assert(badFields.length === 0 && missingFields.length === 0 && badValues.length === 0,
|
|
memberInfo.name + " had the following problems." +
|
|
generateErrorString(badFields, missingFields, badValues, result));
|
|
};
|
|
|
|
// start of test code
|
|
var name = "hello_and_aliases";
|
|
var replTest = new ReplSetTest({name: name, nodes: 4});
|
|
var nodes = replTest.startSet();
|
|
var config = replTest.getReplSetConfig();
|
|
config.members[1].priority = 0;
|
|
config.members[2].priority = 0;
|
|
config.members[2].hidden = true;
|
|
config.members[2].secondaryDelaySecs = 3;
|
|
config.members[2].buildIndexes = false;
|
|
config.members[3].arbiterOnly = true;
|
|
replTest.initiate(config);
|
|
|
|
var agreeOnPrimaryAndSetVersion = function(setVersion) {
|
|
print("Waiting for primary and replica set version " + setVersion);
|
|
|
|
var nodes = replTest.nodes;
|
|
var currPrimary = undefined;
|
|
var lastSetVersion = setVersion;
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
try {
|
|
var helloResult = nodes[i].getDB("admin").runCommand({hello: 1});
|
|
} catch (e) {
|
|
// handle reconnect errors due to step downs
|
|
print("Error while calling hello on " + nodes[i] + ": " + e);
|
|
return false;
|
|
}
|
|
|
|
printjson(helloResult);
|
|
if (!currPrimary)
|
|
currPrimary = helloResult.primary;
|
|
if (!lastSetVersion)
|
|
lastSetVersion = helloResult.setVersion;
|
|
if (helloResult.primary != currPrimary || !currPrimary)
|
|
return false;
|
|
if (helloResult.setVersion != lastSetVersion)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
var primary = replTest.getPrimary();
|
|
var secondaries = replTest.getSecondaries();
|
|
var expectedVersion = replTest.getReplSetConfigFromNode().version;
|
|
assert.soon(function() {
|
|
return agreeOnPrimaryAndSetVersion(expectedVersion);
|
|
}, "Nodes did not initiate in less than a minute", 60000);
|
|
|
|
// Check to see if the information from hello() and its aliases are correct at each node.
|
|
// The checker only checks that the field exists when its value is "has".
|
|
runHelloCmdAndAliases({
|
|
conn: primary,
|
|
name: "primary",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: true,
|
|
secondary: false,
|
|
ok: 1
|
|
},
|
|
wantedFields:
|
|
["hosts", "passives", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"arbiterOnly",
|
|
"passive",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"hidden",
|
|
"tags",
|
|
"buildIndexes"
|
|
]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[0],
|
|
name: "secondary",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: true,
|
|
passive: true,
|
|
ok: 1
|
|
},
|
|
wantedFields:
|
|
["hosts", "passives", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"arbiterOnly",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"hidden",
|
|
"tags",
|
|
"buildIndexes"
|
|
]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[1],
|
|
name: "delayed_secondary",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: true,
|
|
passive: true,
|
|
slaveDelay: 3,
|
|
buildIndexes: false,
|
|
ok: 1
|
|
},
|
|
wantedFields:
|
|
["hosts", "passives", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: ["isWritablePrimary", "arbiterOnly", "tags", "secondaryDelaySecs"]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[2],
|
|
name: "arbiter",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: false,
|
|
arbiterOnly: true,
|
|
ok: 1
|
|
},
|
|
wantedFields:
|
|
["hosts", "passives", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"hidden",
|
|
"tags",
|
|
"buildIndexes",
|
|
"passive"
|
|
]
|
|
});
|
|
|
|
// Reconfigure the replset and make sure the changes are present on all members.
|
|
config = primary.getDB("local").system.replset.findOne();
|
|
config.version = config.version + 1;
|
|
config.members[0].tags = {
|
|
disk: "ssd"
|
|
};
|
|
config.members[1].tags = {
|
|
disk: "ssd"
|
|
};
|
|
config.members[1].hidden = true;
|
|
config.members[2].secondaryDelaySecs = 300000;
|
|
config.members[2].tags = {
|
|
disk: "hdd"
|
|
};
|
|
try {
|
|
result = primary.getDB("admin").runCommand({replSetReconfig: config});
|
|
} catch (e) {
|
|
print(e);
|
|
}
|
|
|
|
primary = replTest.getPrimary();
|
|
secondaries = replTest.getSecondaries();
|
|
expectedVersion = config.version;
|
|
assert.soon(function() {
|
|
return agreeOnPrimaryAndSetVersion(expectedVersion);
|
|
}, "Nodes did not sync in less than a minute", 60000);
|
|
|
|
// check nodes for their new settings
|
|
runHelloCmdAndAliases({
|
|
conn: primary,
|
|
name: "primary2",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: true,
|
|
secondary: false,
|
|
tags: {"disk": "ssd"},
|
|
ok: 1
|
|
},
|
|
wantedFields: ["hosts", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"arbiterOnly",
|
|
"passives",
|
|
"passive",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"hidden",
|
|
"buildIndexes"
|
|
]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[0],
|
|
name: "first_secondary",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: true,
|
|
tags: {"disk": "ssd"},
|
|
passive: true,
|
|
hidden: true,
|
|
ok: 1
|
|
},
|
|
wantedFields: ["hosts", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"arbiterOnly",
|
|
"passives",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"buildIndexes"
|
|
]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[1],
|
|
name: "very_delayed_secondary",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: true,
|
|
tags: {"disk": "hdd"},
|
|
passive: true,
|
|
slaveDelay: 300000,
|
|
buildIndexes: false,
|
|
hidden: true,
|
|
ok: 1
|
|
},
|
|
wantedFields: ["hosts", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: ["isWritablePrimary", "arbiterOnly", "passives", "secondaryDelaySecs"]
|
|
});
|
|
|
|
runHelloCmdAndAliases({
|
|
conn: secondaries[2],
|
|
name: "arbiter",
|
|
goodValues: {
|
|
setName: "hello_and_aliases",
|
|
setVersion: expectedVersion,
|
|
ismaster: false,
|
|
secondary: false,
|
|
arbiterOnly: true,
|
|
ok: 1
|
|
},
|
|
wantedFields: ["hosts", "arbiters", "primary", "me", "maxBsonObjectSize", "localTime"],
|
|
unwantedFields: [
|
|
"isWritablePrimary",
|
|
"slaveDelay",
|
|
"secondaryDelaySecs",
|
|
"hidden",
|
|
"tags",
|
|
"buildIndexes",
|
|
"passive"
|
|
]
|
|
});
|
|
|
|
// force reconfig and ensure all have the same setVersion afterwards
|
|
config = primary.getDB("local").system.replset.findOne();
|
|
primary.getDB("admin").runCommand({replSetReconfig: config, force: true});
|
|
|
|
assert.soon(function() {
|
|
return agreeOnPrimaryAndSetVersion();
|
|
}, "Nodes did not sync in less than a minute after forced reconfig", 60000);
|
|
|
|
replTest.stopSet();
|