190 lines
6.9 KiB
JavaScript
190 lines
6.9 KiB
JavaScript
/**
|
|
* Test the automatic dry-run behavior during setFeatureCompatibilityVersion command,
|
|
* along with the skipDryRun parameter and failpoints for dry-run failures.
|
|
*
|
|
* @tags: [requires_fcv_83]
|
|
*/
|
|
|
|
import {configureFailPoint} from "jstests/libs/fail_point_util.js";
|
|
import {ReplSetTest} from "jstests/libs/replsettest.js";
|
|
import {ShardingTest} from "jstests/libs/shardingtest.js";
|
|
|
|
const failCases = [
|
|
{
|
|
fromFCV: latestFCV,
|
|
toFCV: lastLTSFCV,
|
|
failPointName: "failDowngradeValidationDueToIncompatibleFeature",
|
|
expectedError: ErrorCodes.CannotDowngrade,
|
|
},
|
|
{
|
|
fromFCV: lastLTSFCV,
|
|
toFCV: latestFCV,
|
|
failPointName: "failUpgradeValidationDueToIncompatibleFeature",
|
|
expectedError: ErrorCodes.CannotUpgrade,
|
|
},
|
|
];
|
|
|
|
/**
|
|
* Tests the behavior when automatic dry-run fails during FCV transitions.
|
|
* Ensures the FCV remains unchanged.
|
|
*/
|
|
function testDryRunFailStopsTransition(conn, shardConn, fromFCV, toFCV, failPointName, expectedError) {
|
|
const db = conn.getDB("admin");
|
|
|
|
jsTestLog(`Setting initial FCV to ${fromFCV}.`);
|
|
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: fromFCV, confirm: true}));
|
|
|
|
let failpoint = configureFailPoint(shardConn, failPointName);
|
|
|
|
jsTestLog(`Testing automatic dry-run during FCV transition: ${fromFCV} → ${toFCV}, expecting failure`);
|
|
const result = db.runCommand({setFeatureCompatibilityVersion: toFCV, confirm: true});
|
|
assert.commandFailedWithCode(result, expectedError);
|
|
checkFCV(db, fromFCV); // FCV should remain unchanged
|
|
|
|
failpoint.off();
|
|
jsTestLog("Automatic dry-run failure test completed.");
|
|
|
|
// Reset FCV to latestFCV for consistency across tests
|
|
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
|
|
}
|
|
|
|
/**
|
|
* Tests conflicting parameters `dryRun` and `skipDryRun` in setFCV command. They cannot be true at
|
|
* the same time because skipDryRun is used to avoid the default dryRun in setFCV command
|
|
*/
|
|
function testConflictingParametersWithSkipDryRun(conn) {
|
|
const db = conn.getDB("admin");
|
|
|
|
jsTestLog("Testing conflicting `dryRun` and `skipDryRun` parameters.");
|
|
const result = db.runCommand({
|
|
setFeatureCompatibilityVersion: lastLTSFCV,
|
|
dryRun: true,
|
|
skipDryRun: true,
|
|
});
|
|
assert.commandFailedWithCode(result, ErrorCodes.InvalidOptions);
|
|
|
|
checkFCV(db, latestFCV); // FCV should remain unchanged when the command fails.
|
|
|
|
jsTestLog("Conflicting parameter tests completed.");
|
|
}
|
|
|
|
// Tests a valid downgrade transition using `skipDryRun`, which skips the automatic validation
|
|
// step and completes successfully
|
|
function testSuccessWithSkipDryRun(conn) {
|
|
const db = conn.getDB("admin");
|
|
|
|
jsTestLog("Testing successful FCV downgrade using `skipDryRun` parameter: latestFCV → lastLTSFCV.");
|
|
const skipDryRunSuccessResult = db.runCommand({
|
|
setFeatureCompatibilityVersion: lastLTSFCV,
|
|
skipDryRun: true,
|
|
confirm: true,
|
|
});
|
|
|
|
assert.commandWorked(skipDryRunSuccessResult);
|
|
checkFCV(db, lastLTSFCV); // Ensure the FCV transitioned successfully.
|
|
|
|
// Reset FCV to latestFCV for consistency across tests
|
|
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: latestFCV, confirm: true}));
|
|
}
|
|
/**
|
|
* Tests a downgrade attempt with `skipDryRun` and a failpoint enabled, which simulates an invalid
|
|
* transition and results in a failure, leaving the FCV in a transitional state due to the skipped
|
|
* validation.
|
|
*/
|
|
function testFailureWithSkipDryRun(conn, shardConn, failPointName, expectedError) {
|
|
const db = conn.getDB("admin");
|
|
|
|
let failpoint = configureFailPoint(shardConn, failPointName);
|
|
|
|
jsTestLog("Testing unsuccessful FCV downgrade using `skipDryRun` parameter: latestFCV → lastLTSFCV.");
|
|
const skipDryRunFailResult = db.runCommand({
|
|
setFeatureCompatibilityVersion: lastLTSFCV,
|
|
skipDryRun: true,
|
|
confirm: true,
|
|
});
|
|
assert.commandFailedWithCode(skipDryRunFailResult, expectedError);
|
|
|
|
checkFCV(db, lastLTSFCV, lastLTSFCV); // if dryRun is skipped and an error is raised, the FCV
|
|
// remains in a transitional downgrading state.
|
|
|
|
// If the user runs an explicit dryRun at this point, an error will be thrown and their FCV
|
|
// stays in the transitional state
|
|
assert.commandFailedWithCode(
|
|
db.runCommand({
|
|
setFeatureCompatibilityVersion: lastLTSFCV,
|
|
dryRun: true,
|
|
}),
|
|
expectedError,
|
|
);
|
|
checkFCV(db, lastLTSFCV, lastLTSFCV);
|
|
|
|
failpoint.off();
|
|
|
|
// If the user runs an explicit dryRun at this point, it will succeed but still keep the FCV in
|
|
// the transitional state
|
|
assert.commandWorked(db.runCommand({setFeatureCompatibilityVersion: lastLTSFCV, dryRun: true}));
|
|
checkFCV(db, lastLTSFCV, lastLTSFCV);
|
|
|
|
jsTestLog("SkipDryRun tests 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) {
|
|
jsTestLog(">>> Testing skipDryRun parameter");
|
|
testSuccessWithSkipDryRun(conn);
|
|
testFailureWithSkipDryRun(
|
|
conn,
|
|
shardConn,
|
|
"failDowngradeValidationDueToIncompatibleFeature",
|
|
ErrorCodes.CannotDowngrade,
|
|
);
|
|
|
|
for (const {fromFCV, toFCV, failPointName, expectedError} of failCases) {
|
|
jsTestLog(">>> Testing expected dryRun failure scenario");
|
|
testDryRunFailStopsTransition(conn, shardConn, fromFCV, toFCV, failPointName, expectedError);
|
|
}
|
|
|
|
jsTestLog(">>> Testing conflicting parameters dryRun and skipDryRun");
|
|
testConflictingParametersWithSkipDryRun(conn);
|
|
}
|
|
|
|
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();
|