Files
mongo/jstests/multiVersion/genericSetFCVUsage/set_fcv_dry_run_mode.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

165 lines
5.8 KiB
JavaScript
Raw Normal View History

/**
* Test for both downgrading and upgrading FCV cases using the `dryRun` option of
* the setFeatureCompatibilityVersion command.
*
* @tags: [requires_fcv_83]
*/
import {ReplSetTest} from "jstests/libs/replsettest.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
const successfulCases = [
{fromFCV: latestFCV, toFCV: lastLTSFCV}, // Downgrade from latest to lastLTS
{fromFCV: latestFCV, toFCV: lastContinuousFCV}, // Downgrade from latest to lastContinuous
{fromFCV: lastLTSFCV, toFCV: latestFCV}, // Upgrade from lastLTS to latest
{
fromFCV: lastLTSFCV,
toFCV: lastContinuousFCV,
fromConfigServer: true,
}, // Upgrade from lastLTS to lastContinuous . fromConfigServer is needed because this
// transition is only allowed as part of internal operations (`addShard`).
{fromFCV: lastContinuousFCV, toFCV: latestFCV}, // Upgrade from lastContinuous to latest
{fromFCV: latestFCV, toFCV: latestFCV}, // Same requested and actual version
];
const failCases = [
{
fromFCV: latestFCV,
toFCV: lastLTSFCV,
failPointName: "failDowngradeValidationDueToIncompatibleFeature",
expectedError: ErrorCodes.CannotDowngrade,
},
{
fromFCV: lastLTSFCV,
toFCV: latestFCV,
failPointName: "failUpgradeValidationDueToIncompatibleFeature",
expectedError: ErrorCodes.CannotUpgrade,
},
];
if (lastLTSFCV !== lastContinuousFCV) {
failCases.push({
fromFCV: lastLTSFCV,
toFCV: lastContinuousFCV,
expectedError: 5147403,
});
}
function testSuccessfulDryRun(conn, fromFCV, toFCV, fromConfigServer) {
const db = conn.getDB("admin");
jsTestLog(`Setting initial FCV to ${fromFCV}.`);
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: fromFCV, confirm: true}));
jsTestLog(`Performing dry-run validation for transition from ${fromFCV} to ${toFCV}.`);
const commandObj = {setFeatureCompatibilityVersion: toFCV, dryRun: true};
// Include `fromConfigServer` if specified in the test case
if (fromConfigServer) {
commandObj.fromConfigServer = true;
}
const res = db.runCommand(commandObj);
assert.commandWorked(res, "Dry-run validation did not succeed.");
checkFCV(db, fromFCV); // FCV should remain unchanged post-dry-run
jsTestLog(`Dry-run completed successfully.`);
// Reset FCV to latestFCV for consistency across tests
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
}
function testFailedDryRun(conn, fromFCV, toFCV, failPointName, expectedError, shardConn) {
const db = conn.getDB("admin");
jsTestLog(`Setting initial FCV to ${fromFCV}.`);
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: fromFCV, confirm: true}));
if (failPointName) {
jsTestLog(`Enabling failpoint '${failPointName}' to simulate validation failure.`);
assert.commandWorked(
shardConn.adminCommand({
configureFailPoint: failPointName,
mode: "alwaysOn",
}),
);
}
jsTestLog(`Performing dry-run validation for transition from ${fromFCV} to ${toFCV} expecting failure.`);
const res = db.runCommand({
setFeatureCompatibilityVersion: toFCV,
dryRun: true,
});
jsTestLog("Validating the error code returned from the dry-run.");
assert.commandFailedWithCode(res, expectedError, `Expected error during dry-run validation.`);
checkFCV(db, fromFCV); // FCV should remain unchanged post-dry-run
if (failPointName) {
jsTestLog(`Disabling failpoint '${failPointName}'.`);
assert.commandWorked(
shardConn.adminCommand({
configureFailPoint: failPointName,
mode: "off",
}),
);
}
jsTestLog(`Failure simulation for dry-run validation completed successfully.`);
// Reset FCV to latestFCV for consistency across tests
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
}
// shardConn is used for specifying the shard in which enabling the failpoints
function runDryRunTests(conn, shardConn) {
for (const {fromFCV, toFCV, fromConfigServer} of successfulCases) {
jsTestLog(`>>> Testing dry-run transition: ${fromFCV}${toFCV}`);
testSuccessfulDryRun(conn, fromFCV, toFCV, fromConfigServer);
}
for (const {fromFCV, toFCV, failPointName, expectedError} of failCases) {
jsTestLog(`>>> Testing expected failure scenario: ${fromFCV}${toFCV}`);
testFailedDryRun(conn, fromFCV, toFCV, failPointName, expectedError, shardConn);
}
}
function testAllTopologies() {
jsTestLog("Starting dry-run test for all topologies.");
// Standalone topology tests
{
jsTestLog("Testing standalone topology");
const conn = MongoRunner.runMongod({});
runDryRunTests(conn, conn);
MongoRunner.stopMongod(conn);
jsTestLog(`Dry-run tests for standalone topology completed successfully.`);
}
// Sharded cluster topology tests
{
jsTestLog("Testing sharded cluster topology");
const st = new ShardingTest({shards: 2});
runDryRunTests(st.s, st.rs0.getPrimary());
runDryRunTests(st.s, st.configRS.getPrimary());
st.stop();
jsTestLog(`Dry-run tests for sharded cluster topology completed successfully.`);
}
// Replica set topology tests
{
jsTestLog("Testing replica set topology");
const rst = new ReplSetTest({nodes: 2});
rst.startSet();
rst.initiate();
runDryRunTests(rst.getPrimary(), rst.getPrimary());
rst.stopSet();
jsTestLog(`Dry-run tests for standalone topology completed successfully.`);
}
jsTestLog("Dry-run test execution completed.");
}
testAllTopologies();