0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-30 00:56:44 +01:00
mongodb/jstests/replsets/disconnect_on_legacy_write_to_secondary.js

107 lines
4.0 KiB
JavaScript

/**
* Tests that legacy writes to secondaries result in no answer and a disconnection.
*/
(function() {
"use strict";
load("jstests/libs/fail_point_util.js");
const rst = new ReplSetTest({nodes: [{}, {rsConfig: {priority: 0}}]});
rst.startSet();
rst.initiate();
const primary = rst.getPrimary();
const secondary = rst.getSecondary();
const collname = "disconnect_on_legacy_write_to_secondary";
const coll = primary.getDB("test")[collname];
const secondaryDb = secondary.getDB("test");
const secondaryColl = secondaryDb[collname];
// Never retry on network error, because this test needs to detect the network error.
TestData.skipRetryOnNetworkError = true;
secondary.forceWriteMode('legacy');
assert.commandWorked(coll.insert([{_id: 'deleteme'}, {_id: 'updateme'}]));
rst.awaitReplication();
jsTestLog("Trying legacy insert on secondary");
secondaryColl.insert({_id: 'no_insert_on_secondary'});
let res = assert.throws(() => secondaryDb.adminCommand({ping: 1}));
assert(isNetworkError(res));
// We should automatically reconnect after the failed command.
assert.commandWorked(secondaryDb.adminCommand({ping: 1}));
jsTestLog("Trying legacy update on secondary");
secondaryColl.update({_id: 'updateme'}, {'$set': {x: 1}});
res = assert.throws(() => secondaryDb.adminCommand({ping: 1}));
assert(isNetworkError(res));
// We should automatically reconnect after the failed command.
assert.commandWorked(secondaryDb.adminCommand({ping: 1}));
jsTestLog("Trying legacy remove on secondary");
secondaryColl.remove({_id: 'deleteme'}, {'$set': {x: 1}});
res = assert.throws(() => secondaryDb.adminCommand({ping: 1}));
assert(isNetworkError(res));
// We should automatically reconnect after the failed command.
assert.commandWorked(secondaryDb.adminCommand({ping: 1}));
// Do the stepdown tests on a separate connection to avoid interfering with the
// ReplSetTest mechanism.
const primaryAdmin = primary.getDB("admin");
const primaryDataConn = new Mongo(primary.host);
const primaryDb = primaryDataConn.getDB("test");
const primaryColl = primaryDb[collname];
primaryDataConn.forceWriteMode('legacy');
function getNotMasterLegacyUnackWritesCounter() {
return assert.commandWorked(primaryAdmin.adminCommand({serverStatus: 1}))
.metrics.repl.network.notMasterLegacyUnacknowledgedWrites;
}
function runStepDownTest({description, failpoint, operation}) {
jsTestLog("Enabling failpoint to block " + description + "s");
let failPoint = configureFailPoint(primaryAdmin, failpoint);
let failedLegacyUnackWritesBefore = getNotMasterLegacyUnackWritesCounter();
jsTestLog("Trying legacy " + description + " on stepping-down primary");
operation();
failPoint.wait();
jsTestLog("Within " + description + ": stepping down and disabling failpoint");
assert.commandWorked(primaryAdmin.adminCommand({replSetStepDown: 60, force: true}));
rst.waitForState(primary, ReplSetTest.State.SECONDARY);
failPoint.off();
res = assert.throws(() => primaryDb.adminCommand({ping: 1}));
assert(isNetworkError(res));
// We should automatically reconnect after the failed command.
assert.commandWorked(primaryDb.adminCommand({ping: 1}));
// Validate the number of legacy unacknowledged writes failed due to step down resulted
// in network disconnection.
let failedLegacyUnackWritesAfter = getNotMasterLegacyUnackWritesCounter();
assert.eq(failedLegacyUnackWritesAfter, failedLegacyUnackWritesBefore + 1);
// Allow the primary to be re-elected, and wait for it.
assert.commandWorked(primaryAdmin.adminCommand({replSetFreeze: 0}));
rst.getPrimary();
}
runStepDownTest({
description: "insert",
failpoint: "hangDuringBatchInsert",
operation: () => primaryColl.insert({_id: 'no_insert_on_stepdown'})
});
runStepDownTest({
description: "update",
failpoint: "hangDuringBatchUpdate",
operation: () => primaryColl.update({_id: 'updateme'}, {'$set': {x: 1}})
});
runStepDownTest({
description: "remove",
failpoint: "hangDuringBatchRemove",
operation: () => primaryColl.remove({_id: 'deleteme'}, {'$set': {x: 1}})
});
rst.stopSet();
})();