Files
mongo/jstests/libs/cluster_server_parameter_utils.js

250 lines
10 KiB
JavaScript

/**
* Util functions used by cluster server parameter tests.
*
* When adding new cluster server parameters, do the following:
* 1. Add its name to clusterParameterNames.
* 2. Add the clusterParameter document that's expected as default to clusterParametersDefault.
* 3. Add the clusterParameter document that setClusterParameter is expected to insert after its
* first invocation to clusterParametersInsert.
* 4. Add the clusterParameter document that setClusterParameter is expected to update to after its
* second invocation to clusterParametersUpdate.
*
*/
const clusterParameterNames = ["testStrClusterParameter", "testIntClusterParameter"];
const clusterParametersDefault = [
{
_id: "testStrClusterParameter",
clusterParameterTime: Timestamp(0, 0),
strData: "off",
},
{
_id: "testIntClusterParameter",
clusterParameterTime: Timestamp(0, 0),
intData: 16,
}
];
const clusterParametersInsert = [
{
_id: "testStrClusterParameter",
clusterParameterTime: Timestamp(10, 2),
strData: "on",
},
{
_id: "testIntClusterParameter",
clusterParameterTime: Timestamp(10, 2),
intData: 17,
}
];
const clusterParametersUpdate = [
{
_id: "testStrClusterParameter",
clusterParameterTime: Timestamp(20, 4),
strData: "sleep",
},
{
_id: "testIntClusterParameter",
clusterParameterTime: Timestamp(20, 4),
intData: 18,
}
];
// Set the log level for get/setClusterParameter logging to appear.
function setupNode(conn) {
const adminDB = conn.getDB('admin');
adminDB.setLogLevel(2);
}
function setupReplicaSet(rst) {
setupNode(rst.getPrimary());
rst.getSecondaries().forEach(function(secondary) {
setupNode(secondary);
});
}
function setupSharded(st) {
setupNode(st.s0);
const shards = [st.rs0, st.rs1, st.rs2];
shards.forEach(function(shard) {
setupReplicaSet(shard);
});
}
// TO-DO SERVER-65128: replace this function with a call to setClusterParameter.
// Upserts config.clusterParameters document with w:majority.
function simulateSetClusterParameterReplicaSet(rst, query, update) {
const clusterParametersNS = rst.getPrimary().getDB('config').clusterParameters;
assert.commandWorked(
clusterParametersNS.update(query, update, {upsert: true, writeConcern: {w: "majority"}}));
}
// TO-DO SERVER-65128: replace this function with a call to setClusterParameter.
// Upserts config.clusterParameters document with w:majority into configsvr and all shards.
function simulateSetClusterParameterSharded(st, query, update) {
simulateSetClusterParameterReplicaSet(st.configRS, query, update);
const shards = [st.rs0, st.rs1, st.rs2];
shards.forEach(function(shard) {
simulateSetClusterParameterReplicaSet(shard, query, update);
});
}
// Runs getClusterParameter on a specific mongod or mongos node and returns true/false depending
// on whether .
function runGetClusterParameterNode(conn, getClusterParameterArgs, expectedClusterParameters) {
const adminDB = conn.getDB('admin');
const actualClusterParameters =
assert.commandWorked(adminDB.runCommand({getClusterParameter: getClusterParameterArgs}))
.clusterParameters;
// Sort the returned clusterParameters and the expected clusterParameters by _id.
actualClusterParameters.sort((a, b) => a._id.localeCompare(b._id));
expectedClusterParameters.sort((a, b) => a._id.localeCompare(b._id));
for (let i = 0; i < expectedClusterParameters.length; i++) {
const expectedClusterParameter = expectedClusterParameters[i];
const actualClusterParameter = actualClusterParameters[i];
// Sort both expectedClusterParameter and actualClusterParameter into alphabetical order
// by key.
const sortedExpectedClusterParameter =
Object.keys(expectedClusterParameter).sort().reduce(function(sorted, key) {
sorted[key] = expectedClusterParameter[key];
return sorted;
}, {});
const sortedActualClusterParameter =
Object.keys(actualClusterParameter).sort().reduce(function(sorted, key) {
sorted[key] = actualClusterParameter[key];
return sorted;
}, {});
if (bsonWoCompare(sortedExpectedClusterParameter, sortedActualClusterParameter) !== 0) {
return false;
}
}
return true;
}
// Runs getClusterParameter on each replica set node and asserts that the response matches the
// expected parameter objects on at least a majority of nodes.
function runGetClusterParameterReplicaSet(rst, getClusterParameterArgs, expectedClusterParameters) {
let numMatches = 0;
const numTotalNodes = rst.getSecondaries().length + 1;
if (runGetClusterParameterNode(
rst.getPrimary(), getClusterParameterArgs, expectedClusterParameters)) {
numMatches++;
}
rst.getSecondaries().forEach(function(secondary) {
if (runGetClusterParameterNode(
secondary, getClusterParameterArgs, expectedClusterParameters)) {
numMatches++;
}
});
assert((numMatches / numTotalNodes) > 0.5);
}
// Runs getClusterParameter on mongos and each mongod in each shard replica set.
function runGetClusterParameterSharded(st, getClusterParameterArgs, expectedClusterParameters) {
runGetClusterParameterNode(st.s0, getClusterParameterArgs, expectedClusterParameters);
const shards = [st.rs0, st.rs1, st.rs2];
shards.forEach(function(shard) {
runGetClusterParameterReplicaSet(shard, getClusterParameterArgs, expectedClusterParameters);
});
}
// Tests valid usages of getClusterParameter and verifies that the expected values are returned.
function testValidParameters(conn) {
if (conn instanceof ReplSetTest) {
// Run getClusterParameter in list format and '*' and ensure it returns all default values
// on all nodes in the replica set.
runGetClusterParameterReplicaSet(conn, clusterParameterNames, clusterParametersDefault);
runGetClusterParameterReplicaSet(conn, '*', clusterParametersDefault);
// For each parameter, simulate setClusterParameter and verify that getClusterParameter
// returns the updated value on all nodes in the replica set.
for (let i = 0; i < clusterParameterNames.length; i++) {
query = {_id: clusterParameterNames[i]};
simulateSetClusterParameterReplicaSet(conn, query, clusterParametersInsert[i]);
runGetClusterParameterReplicaSet(
conn, clusterParameterNames[i], [clusterParametersInsert[i]]);
}
// Do the above again to verify that document updates are also handled properly.
for (let i = 0; i < clusterParameterNames.length; i++) {
query = {_id: clusterParameterNames[i]};
simulateSetClusterParameterReplicaSet(conn, query, clusterParametersUpdate[i]);
runGetClusterParameterReplicaSet(
conn, clusterParameterNames[i], [clusterParametersUpdate[i]]);
}
// Finally, run getClusterParameter in list format and '*' and ensure that they now all
// return updated values.
runGetClusterParameterReplicaSet(conn, clusterParameterNames, clusterParametersUpdate);
runGetClusterParameterReplicaSet(conn, '*', clusterParametersUpdate);
} else {
// Run getClusterParameter in list format and '*' and ensure it returns all default values
// on all nodes in the sharded cluster.
runGetClusterParameterSharded(conn, clusterParameterNames, clusterParametersDefault);
runGetClusterParameterSharded(conn, '*', clusterParametersDefault);
// For each parameter, simulate setClusterParameter and verify that getClusterParameter
// returns the updated value on all nodes in the sharded cluster.
for (let i = 0; i < clusterParameterNames.length; i++) {
query = {_id: clusterParameterNames[i]};
simulateSetClusterParameterSharded(conn, query, clusterParametersInsert[i]);
runGetClusterParameterSharded(
conn, clusterParameterNames[i], [clusterParametersInsert[i]]);
}
// Do the above again to verify that document updates are also handled properly.
for (let i = 0; i < clusterParameterNames.length; i++) {
query = {_id: clusterParameterNames[i]};
simulateSetClusterParameterSharded(conn, query, clusterParametersUpdate[i]);
runGetClusterParameterSharded(
conn, clusterParameterNames[i], [clusterParametersUpdate[i]]);
}
// Finally, run getClusterParameter in list format and '*' and ensure that they now all
// return updated values.
runGetClusterParameterSharded(conn, clusterParameterNames, clusterParametersUpdate);
runGetClusterParameterSharded(conn, '*', clusterParametersUpdate);
}
}
// Tests that invalid uses of getClusterParameter fails
function testInvalidParametersNode(conn) {
const adminDB = conn.getDB('admin');
// Assert that specifying a nonexistent parameter returns an error.
assert.commandFailedWithCode(adminDB.runCommand({getClusterParameter: "nonexistentParam"}),
ErrorCodes.NoSuchKey);
assert.commandFailedWithCode(adminDB.runCommand({getClusterParameter: ["nonexistentParam"]}),
ErrorCodes.NoSuchKey);
assert.commandFailedWithCode(
adminDB.runCommand({getClusterParameter: ["testIntClusterParameter", "nonexistentParam"]}),
ErrorCodes.NoSuchKey);
}
// Tests that invalid uses of getClusterParameter fail with the appropriate errors.
function testInvalidParameters(conn) {
if (conn instanceof ReplSetTest) {
testInvalidParametersNode(conn.getPrimary());
conn.getSecondaries().forEach(function(secondary) {
testInvalidParametersNode(secondary);
});
} else {
testInvalidParametersNode(conn.s0);
const shards = [conn.rs0, conn.rs1, conn.rs2];
shards.forEach(function(shard) {
shard.getSecondaries().forEach(function(secondary) {
testInvalidParametersNode(secondary);
});
});
}
}