mongo/jstests/replsets/initial_sync_succeeds_when_syncing_node_removed.js
Zac 591928c619 SERVER-108478 JS formatted by prettier and remove clang-format (#39656)
GitOrigin-RevId: 6c8f6aded47f260aa4f7c231b17dae3302cb1e04
2025-08-21 17:27:09 +00:00

115 lines
4.3 KiB
JavaScript

/**
* Tests that initial sync will continue if the syncing node is removed during syncing.
* This behavior is desired because transient DNS failures can cause the node to falsely believe
* that it is removed.
*
* @tags: [
* ]
*/
import {configureFailPoint, kDefaultWaitForFailPointTimeout} from "jstests/libs/fail_point_util.js";
import {ReplSetTest} from "jstests/libs/replsettest.js";
const testName = TestData.testName;
const rst = new ReplSetTest({name: testName, nodes: [{}]});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
const primaryDb = primary.getDB("test");
const initialSyncSource = primary;
// Add some data to be cloned.
assert.commandWorked(primaryDb.test.insert([{a: 1}, {b: 2}, {c: 3}]));
rst.awaitReplication();
jsTest.log("Adding the initial sync destination node to the replica set");
const initialSyncNode = rst.add({
rsConfig: {priority: 0, votes: 0},
setParameter: {
"failpoint.initialSyncHangBeforeCopyingDatabases": tojson({mode: "alwaysOn"}),
"numInitialSyncAttempts": 1,
"logComponentVerbosity": tojson({replication: {verbosity: 1}}),
"failpoint.forceSyncSourceCandidate": tojson({mode: "alwaysOn", data: {hostAndPort: initialSyncSource.host}}),
},
});
rst.reInitiate();
rst.waitForState(initialSyncNode, ReplSetTest.State.STARTUP_2);
// Set us up to hang before finish so we can check status.
const beforeFinishFailPoint = configureFailPoint(initialSyncNode, "initialSyncHangBeforeFinish");
jsTestLog("Waiting to reach cloning phase of initial sync");
assert.commandWorked(
initialSyncNode.adminCommand({
waitForFailPoint: "initialSyncHangBeforeCopyingDatabases",
timesEntered: 1,
maxTimeMS: kDefaultWaitForFailPointTimeout,
}),
);
jsTestLog("Removing initial sync node");
// Avoid closing the connection when the node transitions to REMOVED.
assert.commandWorked(initialSyncNode.adminCommand({hello: 1, hangUpOnStepDown: false}));
let config = rst.getReplSetConfigFromNode();
const origHost = config.members[1].host;
// This host will never resolve.
config.members[1].host = "always.invalid:27017";
config.version++;
assert.commandWorked(primary.adminCommand({replSetReconfig: config, force: 1}));
jsTestLog("Waiting for initial sync node to realize it is removed.");
assert.soonNoExcept(function () {
assert.commandFailedWithCode(
initialSyncNode.adminCommand({replSetGetStatus: 1}),
ErrorCodes.InvalidReplicaSetConfig,
);
return true;
});
// Release the initial failpoint.
assert.commandWorked(
initialSyncNode.adminCommand({configureFailPoint: "initialSyncHangBeforeCopyingDatabases", mode: "off"}),
);
jsTestLog("Waiting for initial sync to complete.");
beforeFinishFailPoint.wait();
jsTestLog("Initial sync complete. Re-adding node to check initial sync status.");
config.members[1].host = origHost;
config.version++;
assert.commandWorked(primary.adminCommand({replSetReconfig: config, force: 1}));
rst.waitForState(initialSyncNode, ReplSetTest.State.STARTUP_2);
const res = assert.commandWorked(initialSyncNode.adminCommand({replSetGetStatus: 1}));
printjson(res.initialSyncStatus);
assert.eq(res.initialSyncStatus.failedInitialSyncAttempts, 0);
jsTestLog("Re-removing node.");
config.members[1].host = "always.invalid:27017";
config.version++;
assert.commandWorked(primary.adminCommand({replSetReconfig: config, force: 1}));
jsTestLog("Waiting for initial sync node to realize it is removed again.");
assert.soonNoExcept(function () {
assert.commandFailedWithCode(
initialSyncNode.adminCommand({replSetGetStatus: 1}),
ErrorCodes.InvalidReplicaSetConfig,
);
return true;
});
// Add some more data that must be cloned during steady-state replication.
assert.commandWorked(primaryDb.test.insert([{d: 4}, {e: 5}, {f: 6}]));
beforeFinishFailPoint.off();
// Wait until initial sync completion routine is finished.
checkLog.containsJson(initialSyncNode, 4853000);
// Make sure the node is still REMOVED.
assert.commandFailedWithCode(initialSyncNode.adminCommand({replSetGetStatus: 1}), ErrorCodes.InvalidReplicaSetConfig);
jsTestLog("Re-adding initial sync node a final time");
config.members[1].host = origHost;
config.version++;
assert.commandWorked(primary.adminCommand({replSetReconfig: config, force: 1}));
rst.awaitSecondaryNodes(null, [initialSyncNode]);
rst.stopSet();