Files
mongo/jstests/readonly/lib/read_only_test.js
Steve McClure 1ffbc6c2e9 SERVER-109432: Autofix JS var usage to favor let (#40637)
GitOrigin-RevId: 9674b7db36a0f3f650d39c1e3fb2ad6ff2141cfb
2025-08-28 19:21:01 +00:00

217 lines
8.1 KiB
JavaScript

import {ShardingTest} from "jstests/libs/shardingtest.js";
export var StandaloneFixture, ShardedFixture, runReadOnlyTest, zip2, cycleN;
(function () {
StandaloneFixture = function () {};
StandaloneFixture.prototype.runLoadPhase = function runLoadPhase(test) {
this.mongod = MongoRunner.runMongod({});
this.dbpath = this.mongod.dbpath;
test.load(this.mongod.getDB("test")[test.name]);
assert.commandWorked(this.mongod.getDB("local").dropDatabase());
MongoRunner.stopMongod(this.mongod);
};
StandaloneFixture.prototype.runExecPhase = function runExecPhase(test) {
let options = {queryableBackupMode: "", noCleanData: true, dbpath: this.dbpath};
this.mongod = MongoRunner.runMongod(options);
assert.neq(this.mongod, null);
test.exec(this.mongod.getDB("test")[test.name]);
MongoRunner.stopMongod(this.mongod);
};
ShardedFixture = function () {
this.nShards = 3;
this.nConfigs = 3;
};
ShardedFixture.prototype.runLoadPhase = function runLoadPhase(test) {
this.st = new ShardingTest({
mongos: 1,
config: this.nConfigs,
shards: this.nShards,
rs: {nodes: 1},
// By default, our test infrastructure sets the election timeout to a very high value (24
// hours). For this test, we need a shorter election timeout because it relies on nodes
// running an election when they do not detect an active primary. Therefore, we are setting
// the electionTimeoutMillis to its default value.
initiateWithDefaultElectionTimeout: true,
});
// This information will be needed later on to set up the shards on read only mode.
this.dbPaths = [];
this.ports = [];
this.hosts = [];
for (let i = 0; i < this.nShards; ++i) {
let primary = this.st["rs" + i].getPrimary();
this.dbPaths.push(primary.dbpath);
this.ports.push(primary.port);
this.hosts.push(primary.host);
}
jsTest.log("sharding test collection...");
// Use a hashed shard key so we actually hit multiple shards.
this.st.shardColl(test.name, {_id: "hashed"}, false);
test.load(this.st.getDB("test")[test.name]);
};
ShardedFixture.prototype.runExecPhase = function runExecPhase(test) {
const docs = [{_id: 1}];
let shardIdentities = [];
let readOnlyShards = [];
for (let i = 0; i < this.nShards; ++i) {
let primary = this.st["rs" + i].getPrimary();
shardIdentities.push(
primary.getDB("admin").getCollection("system.version").findOne({_id: "shardIdentity"}),
);
assert.neq(null, shardIdentities[i]);
assert.commandWorked(
primary.getDB("_temporary_db").runCommand({
insert: "_temporary_coll" + i,
documents: docs,
writeConcern: {w: "majority"},
}),
);
}
this.st.stopAllShards({noCleanData: true, restart: true, skipValidation: true});
jsTest.log("Restarting shards as read only standalone instances...");
for (let i = 0; i < this.nShards; ++i) {
let dbPath = this.dbPaths[i];
let port = this.ports[i];
jsTestLog("Renaming local.system collection on shard " + i);
let tempMongod = MongoRunner.runMongod({port: port, dbpath: dbPath, noReplSet: true, noCleanData: true});
// Rename the local.system collection to prevent problems with replset configurations.
tempMongod.getDB("local").getCollection("system").renameCollection("_system");
MongoRunner.stopMongod(tempMongod, null, {noCleanData: true, skipValidation: true, wait: true});
let shardIdentity = shardIdentities[i];
let host = this.hosts[i];
// Change the connection string format so the router can create a standalone targeter
// instead of a replica set targeter.
this.st.config.shards.update({_id: shardIdentity.shardName}, {$set: {host: host}});
// Restart the shard as standalone on read only mode.
let configFileStr =
"sharding:\n _overrideShardIdentity: '" + tojson(shardIdentity).replace(/\s+/g, " ") + "'";
// Use the os-specific path delimiter.
jsTestLog("Seting up shard " + i + " with new shard identity " + tojson(shardIdentity));
let delim = _isWindows() ? "\\" : "/";
let configFilePath = dbPath + delim + "config-for-shard-" + i + ".yml";
writeFile(configFilePath, configFileStr);
readOnlyShards.push(
MongoRunner.runMongod({
config: configFilePath,
dbpath: dbPath,
port: port,
queryableBackupMode: "",
restart: true,
shardsvr: "",
}),
);
}
// Restart the config server and the router so they can reload the shard registry.
jsTest.log("Restarting the config server...");
for (let i = 0; i < this.nConfig; ++i) {
this.st.restartConfigServer(i);
}
jsTest.log("Restarting mongos...");
this.st.restartMongos(0);
test.exec(this.st.getDB("test")[test.name]);
for (let i = 0; i < this.nShards; ++i) {
let dbPath = this.dbPaths[i];
let port = this.ports[i];
// Stop the read only shards.
MongoRunner.stopMongod(readOnlyShards[i], null, {noCleanData: true, skipValidation: true, wait: true});
// Run a temporary mongod to rename the local.system collection.
let tempMongod = MongoRunner.runMongod({port: port, dbpath: dbPath, noReplSet: true, noCleanData: true});
tempMongod.getDB("local").getCollection("_system").renameCollection("system", true);
MongoRunner.stopMongod(tempMongod, null, {noCleanData: true, skipValidation: true, wait: true});
let shardIdentity = shardIdentities[i];
let host = this.hosts[i];
this.st.config.shards.update(
{_id: shardIdentity.shardName},
{$set: {host: shardIdentity.shardName + "/" + host}},
);
// Restart the shard to have a well behaved departure.
this.st.restartShardRS(i);
}
// Restart the config server and the router so the shard registry refreshes and enable the RSM
// again.
for (let i = 0; i < this.nConfigs; ++i) {
this.st.restartConfigServer(i);
}
this.st.restartMongos(0);
this.st.stop();
};
runReadOnlyTest = function (test) {
printjson(test);
assert.eq(typeof test.exec, "function");
assert.eq(typeof test.load, "function");
assert.eq(typeof test.name, "string");
let fixtureType = TestData.fixture || "standalone";
let fixture = null;
if (fixtureType === "standalone") {
fixture = new StandaloneFixture();
} else if (fixtureType === "sharded") {
fixture = new ShardedFixture();
} else {
throw new Error("fixtureType must be one of either 'standalone' or 'sharded'");
}
jsTest.log("starting load phase for test: " + test.name);
fixture.runLoadPhase(test);
jsTest.log("starting execution phase for test: " + test.name);
fixture.runExecPhase(test);
};
cycleN = function* (arr, N) {
for (let i = 0; i < N; ++i) {
yield arr[i % arr.length];
}
};
zip2 = function* (iter1, iter2) {
let n1 = iter1.next();
let n2 = iter2.next();
while (!n1.done || !n2.done) {
let res = [];
if (!n1.done) {
res.push(n1.value);
n1 = iter1.next();
}
if (!n2.done) {
res.push(n2.value);
n2 = iter2.next();
}
yield res;
}
};
})();