mongo/jstests/sharding/database_versioning_all_commands.js
Pol Piñol Castuera c73dc85799 SERVER-125916 SERVER-104976 Remove the repairShardedCollectionChunksHistory command (#53105)
GitOrigin-RevId: 5d1fc8602e0ad82e094d1a94c249473978309cde
2026-05-14 09:51:56 +00:00

1704 lines
77 KiB
JavaScript

/**
* Specifies for each command whether it is expected to send a databaseVersion, and verifies that
* the commands match the specification.
*
* Each command is executed against two different scenarios: after movePrimary, and after
* dropDatabase + recreate on a different primary shard; to verify that the command behaves correctly
* when run with a stale dbVersion.
*
* Each command must have exactly one corresponding test defined. Each defined test case must
* correspond to an existing command. The allowable fields for the test cases are as follows:
*
* - 'run': This is the specified test case that will be executed for each command.
* - 'skip': Use this field to skip the execution of the test case, along with a justification.
* It's important to note that this field doesn't bypass command validation; it only skips the
* actual run.
* - 'explain': This field is optional and is used to test the explain command on the specified
* test case.
* - 'conditional': If you set this field to true, the test case will skip the validation that
* ensures all test cases match existing commands. This is useful for commands that only exist
* in enterprise modules, for instance.
* - 'skipMultiversion': If you set this field to true, the test case will skip running in
* multiversion suites. This is useful if you have a command that existed behind a feature flag
* in the previous version and is now enabled.
*
* Each 'run' (or 'explain') test case object can additionally specify:
* - 'checkResponse': An optional function(res, context) called after a successful command to
* validate the response content. 'context' is an object with 'afterDropRecreate' (boolean)
* indicating which test scenario is running.
*
* @tags: [
* resource_intensive,
* ]
*/
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
import {ShardingTest} from "jstests/libs/shardingtest.js";
import {
commandsAddedToMongodSinceLastLTS,
commandsRemovedFromMongodSinceLastLTS,
} from "jstests/sharding/libs/last_lts_mongod_commands.js";
import {
commandsAddedToMongosSinceLastLTS,
commandsRemovedFromMongosSinceLastLTS,
} from "jstests/sharding/libs/last_lts_mongos_commands.js";
function getNewDbName(dbName) {
if (!getNewDbName.counter) {
getNewDbName.counter = 0;
}
getNewDbName.counter++;
return "db" + getNewDbName.counter;
}
function assertMatchingDatabaseVersion(conn, dbName, dbVersion) {
const res = conn.adminCommand({getDatabaseVersion: dbName});
assert.commandWorked(res);
assert.eq(dbVersion, res.dbVersion);
}
function containsCollection(shard, dbName, collName) {
const res = shard.getDB(dbName).runCommand({listCollections: 1});
assert.commandWorked(res);
const collections = res.cursor.firstBatch;
for (const collection of collections) {
if (collection["name"] === collName) {
return true;
}
}
return false;
}
function toArray(what) {
if (Array.isArray(what)) {
return what;
}
return [what];
}
function validateTestCase(testCase, validateSendsDbVersion) {
assert(
testCase.skip || testCase.run,
"must specify exactly one of 'skip' or 'run' for test case " + tojson(testCase),
);
if (testCase.skip) {
for (const key of Object.keys(testCase)) {
assert(
key === "skip" || key === "conditional",
"if a test case specifies 'skip', it must not specify any other fields besides 'conditional': " +
key +
": " +
tojson(testCase),
);
}
return;
}
for (const test of toArray(testCase.run)) {
validateCommandTestCase(test, validateSendsDbVersion);
}
if (testCase.explain) {
for (const test of toArray(testCase.explain)) {
validateCommandTestCase(test, validateSendsDbVersion);
}
}
}
function validateCommandTestCase(testCase, validateSendsDbVersion) {
assert(testCase.command, "must specify 'command' for test case " + tojson(testCase));
if (validateSendsDbVersion) {
// Check that required fields are present.
assert(
testCase.hasOwnProperty("sendsDbVersion"),
"must specify 'sendsDbVersion' for test case " + tojson(testCase),
);
}
// Check that all present fields are of the correct type.
assert(typeof testCase.command === "function");
assert(testCase.runsAgainstAdminDb ? typeof testCase.runsAgainstAdminDb === "boolean" : true);
if (validateSendsDbVersion) {
assert(typeof testCase.sendsDbVersion === "boolean");
}
assert(testCase.explicitlyCreateCollection ? typeof testCase.explicitlyCreateCollection === "boolean" : true);
assert(testCase.expectNonEmptyCollection ? typeof testCase.expectNonEmptyCollection === "boolean" : true);
assert(
testCase.cleanUp ? typeof testCase.cleanUp === "function" : true,
"cleanUp must be a function: " + tojson(testCase),
);
assert(
testCase.checkResponse ? typeof testCase.checkResponse === "function" : true,
"checkResponse must be a function: " + tojson(testCase),
);
}
function testCommandAfterMovePrimary(testCase, connection, st, dbName, collName) {
const primaryShardBefore = st.getPrimaryShard(dbName);
const primaryShardAfter = st.getOther(primaryShardBefore);
const dbVersionBefore = st.s0.getDB("config").getCollection("databases").findOne({_id: dbName}).version;
if (testCase.explicitlyCreateCollection) {
assert.commandWorked(primaryShardBefore.getDB(dbName).runCommand({create: collName}));
}
if (testCase.expectNonEmptyCollection) {
assert.commandWorked(primaryShardBefore.getDB(dbName).runCommand({insert: collName, documents: [{x: 0}]}));
}
// Ensure all nodes know the dbVersion before the movePrimary.
assert.commandWorked(st.s0.adminCommand({flushRouterConfig: 1}));
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
if (!isAuthoritativeShardsEnabled(primaryShardBefore)) {
assert.commandWorked(primaryShardBefore.adminCommand({_flushDatabaseCacheUpdates: dbName}));
}
if (!isAuthoritativeShardsEnabled(primaryShardAfter)) {
assert.commandWorked(primaryShardAfter.adminCommand({_flushDatabaseCacheUpdates: dbName}));
}
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionBefore);
// With authoritative shards, only the primary shard has the database version. Non-primary
// shards should not have the database metadata.
if (isAuthoritativeShardsEnabled(primaryShardAfter)) {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, {});
} else {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionBefore);
}
// Run movePrimary through the second mongos.
assert.commandWorked(st.s1.adminCommand({movePrimary: dbName, to: primaryShardAfter.name}));
const dbVersionAfter = st.s1.getDB("config").getCollection("databases").findOne({_id: dbName}).version;
// After the movePrimary, the old primary shard should have cleared/removed the dbVersion.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
// With authoritative shards, the new primary should have the new version immediately after
// movePrimary since the DDL populates the shard catalog.
if (isAuthoritativeShardsEnabled(primaryShardAfter)) {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, {});
}
const command = testCase.command(dbName, collName, dbVersionBefore, dbVersionAfter);
let targetConnection = connection;
if (testCase.runOnNewPrimaryShard) {
targetConnection = primaryShardAfter;
} else if (testCase.runOnOldPrimaryShard) {
targetConnection = primaryShardBefore;
}
jsTest.log(
"testing command " +
tojson(command) +
" after movePrimary; primary shard before: " +
primaryShardBefore +
", database version before: " +
tojson(dbVersionBefore) +
", primary shard after: " +
primaryShardAfter +
", target connection: " +
targetConnection,
);
// Run the test case's command.
const res = targetConnection.getDB(testCase.runsAgainstAdminDb ? "admin" : dbName).runCommand(command);
if (testCase.expectedFailureCode) {
assert.commandFailedWithCode(res, testCase.expectedFailureCode);
} else {
assert.commandWorked(res);
if (testCase.checkResponse) {
testCase.checkResponse(res, {afterDropRecreate: false});
}
}
// If this command does not go through the router then there is no need to check if they are
// updated
if (connection === st.s0 || connection === st.s1 || connection === st.s) {
if (testCase.sendsDbVersion) {
// If the command participates in database versioning:
// - The mongos and the new primary shard should now know the new dbVersion.
// - With authoritative shards, the old primary shard no longer has any version
// (metadata was removed by movePrimary DDL).
// - Without authoritative shards, the old primary shard refreshes to the new version.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionAfter);
if (isAuthoritativeShardsEnabled(primaryShardBefore)) {
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
} else {
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionAfter);
}
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
// If the command does not participate in database versioning:
// - The mongos should have targeted the old primary shard but not attached a dbVersion.
// - The old primary shard should have cleared/removed its dbVersion.
// - With authoritative shards, the new primary has the version (DDL populated it).
// - Without authoritative shards, the new primary shard should have cleared its version.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
if (isAuthoritativeShardsEnabled(primaryShardAfter)) {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, {});
}
}
}
if (testCase.cleanUp) {
testCase.cleanUp(st.s0, dbName, collName);
} else {
assert(st.s0.getDB(dbName).getCollection(collName).drop());
}
}
function testCommandAfterDropRecreateDatabase(testCase, connection, st) {
const dbName = getNewDbName();
const collName = "foo";
// Create the database by creating a collection in it.
assert.commandWorked(st.s0.getDB(dbName).createCollection(collName));
const dbVersionBefore = st.s0.getDB("config").getCollection("databases").findOne({_id: dbName}).version;
const primaryShardBefore = st.getPrimaryShard(dbName);
const primaryShardAfter = st.getOther(primaryShardBefore);
// Ensure the router and primary shard know the dbVersion before the drop/recreate database.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionBefore);
// Non-primary shard should not have the database version.
assertMatchingDatabaseVersion(primaryShardAfter, dbName, {});
// Drop and recreate the database through the second mongos.
assert.commandWorked(st.s1.getDB(dbName).dropDatabase());
assert.commandWorked(st.s1.adminCommand({enableSharding: dbName, primaryShard: primaryShardAfter.shardName}));
const dbVersionAfter = st.s1.getDB("config").getCollection("databases").findOne({_id: dbName}).version;
if (testCase.explicitlyCreateCollection) {
assert.commandWorked(primaryShardAfter.getDB(dbName).runCommand({create: collName}));
}
if (testCase.expectNonEmptyCollection) {
assert.commandWorked(primaryShardAfter.getDB(dbName).runCommand({insert: collName, documents: [{x: 0}]}));
}
// The only change after the drop/recreate database should be that the old primary shard should
// have cleared its dbVersion. With authoritative shards, the new primary should already have
// the new version.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
if (isAuthoritativeShardsEnabled(primaryShardAfter)) {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
}
const command = testCase.command(dbName, collName, dbVersionBefore, dbVersionAfter);
let targetConnection = connection;
if (testCase.runOnNewPrimaryShard) {
targetConnection = primaryShardAfter;
} else if (testCase.runOnOldPrimaryShard) {
targetConnection = primaryShardBefore;
}
jsTest.log(
"testing command " +
tojson(command) +
" after drop/recreate database; primary shard before: " +
primaryShardBefore +
", database version before: " +
tojson(dbVersionBefore) +
", primary shard after: " +
primaryShardAfter +
", target connection: " +
targetConnection,
);
// Run the test case's command.
const res = targetConnection.getDB(testCase.runsAgainstAdminDb ? "admin" : dbName).runCommand(command);
if (testCase.expectedFailureCode) {
assert.commandFailedWithCode(res, testCase.expectedFailureCode);
} else {
assert.commandWorked(res);
if (testCase.checkResponse) {
testCase.checkResponse(res, {afterDropRecreate: true});
}
}
// If this command does not go through the router then there is no need to check if they are
// updated
if (connection === st.s0 || connection === st.s1 || connection === st.s) {
if (testCase.sendsDbVersion) {
// If the command participates in database versioning:
// - The mongos and the new primary shard should now know the new dbVersion.
// - With authoritative shards, the old primary shard no longer has any version
// (metadata was removed by dropDatabase).
// - Without authoritative shards, the old primary shard refreshes to the new version.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionAfter);
if (isAuthoritativeShardsEnabled(primaryShardBefore)) {
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
} else {
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionAfter);
}
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
// If the command does not participate in database versioning:
// - The mongos should have targeted the old primary shard but not attached a dbVersion.
// - The old primary shard should have cleared/removed its dbVersion.
// - With authoritative shards, the new primary has the version (DDL populated it).
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
if (isAuthoritativeShardsEnabled(primaryShardAfter)) {
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
}
}
}
// Clean up.
if (testCase.cleanUp) {
testCase.cleanUp(st.s0, dbName, collName);
} else {
assert(st.s0.getDB(dbName).getCollection(collName).drop());
}
assert.commandWorked(st.s0.getDB(dbName).dropDatabase());
}
const allTestCases = {
mongos: {
_clusterQueryWithoutShardKey: {skip: "executed locally on a mongos (not sent to any remote node)"},
_clusterWriteWithoutShardKey: {skip: "executed locally on a mongos (not sent to any remote node)"},
_hashBSONElement: {skip: "executes locally on mongos (not sent to any remote node)"},
_isSelf: {skip: "executes locally on mongos (not sent to any remote node)"},
_killOperations: {skip: "executes locally on mongos (not sent to any remote node)"},
_mergeAuthzCollections: {skip: "always targets the config server"},
_mongotConnPoolStats: {skip: "not on a user database", conditional: true},
_dropConnectionsToMongot: {skip: "not on a user database", conditional: true},
_mirrorMaestroConnPoolStats: {skip: "not on a user database", conditional: true},
_dropMirrorMaestroConnections: {skip: "not on a user database", conditional: true},
_flushShardRegistry: {skip: "internal command"},
abortMoveCollection: {skip: "always targets the config server"},
abortReshardCollection: {skip: "always targets the config server"},
abortRewriteCollection: {skip: "always targets the config server"},
abortTransaction: {skip: "unversioned and uses special targetting rules"},
abortUnshardCollection: {skip: "always targets the config server"},
addShard: {skip: "not on a user database"},
addShardToZone: {skip: "not on a user database"},
aggregate: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
aggregate: collName,
pipeline: [{$match: {x: 1}}],
cursor: {batchSize: 10},
};
},
checkResponse: function (res) {
assert.eq(res.cursor.firstBatch.length, 0, "aggregate should return empty results");
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
explain: {
aggregate: collName,
pipeline: [{$match: {x: 1}}],
cursor: {batchSize: 10},
},
};
},
},
},
analyze: {
skip: "unimplemented. Serves only as a stub.",
}, // TODO SERVER-68055: Extend test to work with analyze
analyzeShardKey: {
run: {
runsAgainstAdminDb: true,
sendsDbVersion: true,
explicitlyCreateCollection: true,
expectNonEmptyCollection: true,
// The command should fail while calculating the read and write distribution metrics
// since the cardinality of the shard key is less than analyzeShardKeyNumRanges
// which defaults to 100.
expectedFailureCode: 4952606,
command: function (dbName, collName) {
return {analyzeShardKey: dbName + "." + collName, key: {_id: 1}};
},
},
},
appendOplogNote: {skip: "unversioned and executes on all shards"},
authenticate: {skip: "does not forward command to primary shard"},
autoSplitVector: {skip: "does not forward command to primary shard"},
balancerCollectionStatus: {skip: "does not forward command to primary shard"},
balancerStart: {skip: "not on a user database"},
balancerStatus: {skip: "not on a user database"},
balancerStop: {skip: "not on a user database"},
buildInfo: {skip: "executes locally on mongos (not sent to any remote node)"},
bulkWrite: {
run: {
sendsDbVersion: true,
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
bulkWrite: 1,
ops: [{insert: 0, document: {_id: 1}}],
nsInfo: [{ns: dbName + "." + collName}],
};
},
},
skipMultiversion: true,
},
checkMetadataConsistency: {
run: {
sendsDbVersion: true,
runsAgainstAdminDb: false,
command: function (dbName, collName) {
return {checkMetadataConsistency: 1};
},
},
},
cleanupStructuredEncryptionData: {skip: "requires encrypted collections"},
clearJumboFlag: {skip: "does not forward command to primary shard"},
clearLog: {skip: "executes locally on mongos (not sent to any remote node)"},
collMod: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {collMod: collName};
},
},
},
collStats: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {collStats: collName};
},
},
},
commitReshardCollection: {skip: "always targets the config server"},
commitShardRemoval: {skip: "not on a user database"},
commitTransaction: {skip: "unversioned and uses special targetting rules"},
commitTransitionToDedicatedConfigServer: {skip: "not on a user database"},
compact: {skip: "not allowed through mongos"},
compactStructuredEncryptionData: {skip: "requires encrypted collections"},
configureCollectionBalancing: {skip: "always targets the config server"},
configureFailPoint: {skip: "executes locally on mongos (not sent to any remote node)"},
configureQueryAnalyzer: {skip: "always targets the config server"},
connPoolStats: {skip: "executes locally on mongos (not sent to any remote node)"},
connPoolSync: {skip: "executes locally on mongos (not sent to any remote node)"},
connectionStatus: {skip: "executes locally on mongos (not sent to any remote node)"},
convertToCapped: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {convertToCapped: collName, size: 8192};
},
},
},
coordinateCommitTransaction: {skip: "unimplemented. Serves only as a stub."},
count: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {count: collName, query: {x: 1}};
},
checkResponse: function (res) {
assert.eq(res.n, 0, "count should return 0");
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {explain: {count: collName, query: {x: 1}}};
},
},
},
cpuload: {skip: "executes locally on mongos (not sent to any remote node)"},
create: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {create: collName};
},
},
},
createIndexes: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {createIndexes: collName, indexes: [{key: {a: 1}, name: "index"}]};
},
},
},
createSearchIndexes: {skip: "executes locally on mongos", conditional: true},
createRole: {skip: "always targets the config server"},
createUnsplittableCollection: {
skip: "Test command that which functionality will be integrated into createCollection",
},
createUser: {skip: "always targets the config server"},
currentOp: {skip: "not on a user database"},
dataSize: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {dataSize: dbName + "." + collName};
},
},
},
dbStats: {
run: {
// dbStats is always broadcast to all shards
sendsDbVersion: false,
command: function (dbName, collName) {
return {dbStats: 1, scale: 1};
},
},
},
delete: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {delete: collName, deletes: [{q: {_id: 1}, limit: 1}]};
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {explain: {delete: collName, deletes: [{q: {_id: 1}, limit: 1}]}};
},
},
},
distinct: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {distinct: collName, key: "x"};
},
checkResponse: function (res) {
assert.eq(res.values.length, 0, "distinct should return empty values");
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {explain: {distinct: collName, key: "x"}};
},
},
},
drop: {skip: "does not forward command to primary shard"},
dropAllRolesFromDatabase: {skip: "always targets the config server"},
dropAllUsersFromDatabase: {skip: "always targets the config server"},
dropConnections: {skip: "not on a user database"},
dropDatabase: {skip: "drops the database from the cluster, changing the UUID"},
dropIndexes: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {dropIndexes: collName, index: "*"};
},
},
},
dropRole: {skip: "always targets the config server"},
dropSearchIndex: {skip: "executes locally on mongos", conditional: true},
dropUser: {skip: "always targets the config server"},
echo: {skip: "does not forward command to primary shard"},
enableSharding: {skip: "does not forward command to primary shard"},
endSessions: {skip: "goes through the cluster write path"},
eseRotateActiveKEK: {skip: "executes locally on mongos (not sent to any remote node)", conditional: true},
explain: {skip: "already tested by each CRUD command through the 'explain' field"},
features: {skip: "executes locally on mongos (not sent to any remote node)"},
filemd5: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {filemd5: ObjectId(), root: collName};
},
},
},
find: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {find: collName, filter: {x: 1}};
},
checkResponse: function (res) {
assert.eq(res.cursor.firstBatch.length, 0, "find should return empty results");
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {explain: {find: collName, filter: {x: 1}}};
},
},
},
findAndModify: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {findAndModify: collName, query: {_id: 0}, remove: true};
},
},
explain: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {explain: {findAndModify: collName, query: {_id: 0}, remove: true}};
},
},
},
flushRouterConfig: {skip: "executes locally on mongos (not sent to any remote node)"},
fsync: {skip: "broadcast to all shards"},
fsyncUnlock: {skip: "broadcast to all shards"},
getAuditConfig: {skip: "not on a user database", conditional: true},
getClusterParameter: {skip: "always targets the config server"},
getCmdLineOpts: {skip: "executes locally on mongos (not sent to any remote node)"},
getDatabaseVersion: {skip: "executes locally on mongos (not sent to any remote node)"},
getDefaultRWConcern: {skip: "executes locally on mongos (not sent to any remote node)"},
getDiagnosticData: {skip: "executes locally on mongos (not sent to any remote node)"},
getESERotateActiveKEKStatus: {
skip: "executes locally on mongos (not sent to any remote node)",
conditional: true,
},
getTransitionToDedicatedConfigServerStatus: {skip: "not on a user database"},
getLog: {skip: "executes locally on mongos (not sent to any remote node)"},
getMore: {skip: "requires a previously established cursor"},
getParameter: {skip: "executes locally on mongos (not sent to any remote node)"},
getQueryableEncryptionCountInfo: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
getQueryableEncryptionCountInfo: collName,
tokens: [
{
tokens: [
{
"s": BinData(0, "lUBO7Mov5Sb+c/D4cJ9whhhw/+PZFLCk/AQU2+BpumQ="),
},
],
},
],
"queryType": "insert",
};
},
},
},
getShardMap: {skip: "executes locally on mongos (not sent to any remote node)"},
getShardVersion: {skip: "executes locally on mongos (not sent to any remote node)"},
grantPrivilegesToRole: {skip: "always targets the config server"},
grantRolesToRole: {skip: "always targets the config server"},
grantRolesToUser: {skip: "always targets the config server"},
hello: {skip: "executes locally on mongos (not sent to any remote node)"},
hostInfo: {skip: "executes locally on mongos (not sent to any remote node)"},
insert: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {insert: collName, documents: [{_id: 1}]};
},
},
},
invalidateUserCache: {skip: "executes locally on mongos (not sent to any remote node)"},
isdbgrid: {skip: "executes locally on mongos (not sent to any remote node)"},
isMaster: {skip: "executes locally on mongos (not sent to any remote node)"},
killCursors: {skip: "requires a previously established cursor"},
killAllSessions: {skip: "always broadcast to all hosts in the cluster"},
killAllSessionsByPattern: {skip: "always broadcast to all hosts in the cluster"},
killOp: {skip: "does not forward command to primary shard"},
killSessions: {skip: "always broadcast to all hosts in the cluster"},
listCollections: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {listCollections: 1};
},
checkResponse: function (res, context) {
if (context.afterDropRecreate) {
assert.eq(
res.cursor.firstBatch.length,
0,
"listCollections should return 0 collections after drop/recreate",
);
} else {
assert.gte(
res.cursor.firstBatch.length,
1,
"listCollections should return at least 1 collection after movePrimary",
);
}
},
},
},
listCommands: {skip: "executes locally on mongos (not sent to any remote node)"},
listDatabases: {skip: "does not forward command to primary shard"},
listIndexes: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {listIndexes: collName};
},
checkResponse: function (res) {
assert.gte(res.cursor.firstBatch.length, 1, "listIndexes should return at least the _id index");
},
},
},
listSearchIndexes: {skip: "executes locally on mongos", conditional: true},
listShards: {skip: "does not forward command to primary shard"},
lockInfo: {skip: "not on a user database"},
logApplicationMessage: {skip: "not on a user database", conditional: true},
logMessage: {skip: "not on a user database"},
logRotate: {skip: "executes locally on mongos (not sent to any remote node)"},
logout: {skip: "not on a user database"},
mapReduce: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
mapReduce: collName,
map: function mapFunc() {
emit(this.x, 1);
},
reduce: function reduceFunc(key, values) {
return Array.sum(values);
},
out: "inline",
};
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
explain: {
mapReduce: collName,
map: function mapFunc() {
emit(this.x, 1);
},
reduce: function reduceFunc(key, values) {
return Array.sum(values);
},
out: "inline",
},
};
},
},
},
mergeAllChunksOnShard: {skip: "does not forward command to primary shard"},
mergeChunks: {skip: "does not forward command to primary shard"},
moveChunk: {skip: "does not forward command to primary shard"},
moveCollection: {skip: "does not forward command to primary shard"},
movePrimary: {skip: "reads primary shard from sharding catalog with readConcern: local"},
moveRange: {skip: "does not forward command to primary shard"},
multicast: {skip: "does not forward command to primary shard"},
netstat: {skip: "executes locally on mongos (not sent to any remote node)"},
oidcListKeys: {skip: "executes locally on mongos (not sent to any remote node)", conditional: true},
oidcRefreshKeys: {skip: "executes locally on mongos (not sent to any remote node)", conditional: true},
ping: {skip: "executes locally on mongos (not sent to any remote node)"},
planCacheClear: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {planCacheClear: collName};
},
},
},
planCacheClearFilters: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {planCacheClearFilters: collName};
},
},
},
planCacheListFilters: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {planCacheListFilters: collName};
},
},
},
planCacheSetFilter: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {planCacheSetFilter: collName, query: {_id: "A"}, indexes: [{_id: 1}]};
},
},
},
profile: {skip: "not supported in mongos"},
reapLogicalSessionCacheNow: {skip: "is a no-op on mongos"},
recreateRangeDeletionTasks: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {recreateRangeDeletionTasks: collName, skipEmptyRanges: true};
},
},
},
refineCollectionShardKey: {skip: "not on a user database"},
refreshLogicalSessionCacheNow: {skip: "goes through the cluster write path"},
refreshSessions: {skip: "executes locally on mongos (not sent to any remote node)"},
releaseMemory: {skip: "requires a previously established cursor"},
removeShard: {skip: "not on a user database"},
removeShardFromZone: {skip: "not on a user database"},
renameCollection: {
run: {
runsAgainstAdminDb: true,
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {
renameCollection: dbName + "." + collName,
to: dbName + "." + collName + "_renamed",
};
},
cleanUp: function (mongosConn, dbName, collName) {
assert(
mongosConn
.getDB(dbName)
.getCollection(collName + "_renamed")
.drop(),
);
},
},
},
replicateSearchIndexCommand: {skip: "internal command for testing only"},
replSetGetStatus: {skip: "not supported in mongos"},
resetPlacementHistory: {skip: "always targets the config server"},
reshardCollection: {skip: "does not forward command to primary shard"},
revokePrivilegesFromRole: {skip: "always targets the config server"},
revokeRolesFromRole: {skip: "always targets the config server"},
revokeRolesFromUser: {skip: "always targets the config server"},
rewriteCollection: {skip: "requires sharded collection"},
rolesInfo: {skip: "always targets the config server"},
rotateCertificates: {skip: "executes locally on mongos (not sent to any remote node)"},
rotateFTDC: {skip: "executes locally on mongos (not sent to any remote node)"},
saslContinue: {skip: "not on a user database"},
saslStart: {skip: "not on a user database"},
serverStatus: {skip: "executes locally on mongos (not sent to any remote node)"},
setAllowMigrations: {skip: "not on a user database"},
setAuditConfig: {skip: "not on a user database", conditional: true},
setDefaultRWConcern: {skip: "always targets the config server"},
setIndexCommitQuorum: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
// The command should fail if there is no active index build on the collection.
expectedFailureCode: ErrorCodes.IndexNotFound,
command: function (dbName, collName) {
return {
setIndexCommitQuorum: collName,
indexNames: ["index"],
commitQuorum: "majority",
};
},
},
},
setFeatureCompatibilityVersion: {skip: "not on a user database"},
setProfilingFilterGlobally: {skip: "executes locally on mongos (not sent to any remote node)"},
setParameter: {skip: "executes locally on mongos (not sent to any remote node)"},
setClusterParameter: {skip: "always targets the config server"},
setQuerySettings: {skip: "not on a user database"},
removeQuerySettings: {skip: "not on a user database"},
setUserWriteBlockMode: {skip: "executes locally on mongos (not sent to any remote node)"},
shardCollection: {skip: "does not forward command to primary shard"},
shardDrainingStatus: {skip: "not on a user database"},
shutdown: {skip: "does not forward command to primary shard"},
split: {
run: {
sendsDbVersion: false,
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
split: dbName + "." + collName,
middle: {_id: 0},
};
},
expectedFailureCode: ErrorCodes.NamespaceNotSharded,
},
},
splitVector: {skip: "does not forward command to primary shard"},
getTrafficRecordingStatus: {skip: "executes locally on targeted node"},
startRecordingTraffic: {skip: "Renamed to startTrafficRecording"},
stopRecordingTraffic: {skip: "Renamed to stopTrafficRecording"},
startShardDraining: {skip: "not on a user database"},
startTrafficRecording: {skip: "executes locally on mongos (not sent to any remote node)"},
startTransitionToDedicatedConfigServer: {skip: "not on a user database"},
startSession: {skip: "executes locally on mongos (not sent to any remote node)"},
stopShardDraining: {skip: "not on a user database"},
stopTrafficRecording: {skip: "executes locally on mongos (not sent to any remote node)"},
stopTransitionToDedicatedConfigServer: {skip: "not on a user database"},
testDeprecation: {skip: "executes locally on mongos (not sent to any remote node)"},
testDeprecationInVersion2: {skip: "executes locally on mongos (not sent to any remote node)"},
testInternalTransactions: {skip: "executes locally on mongos (not sent to any remote node)"},
testRemoval: {skip: "executes locally on mongos (not sent to any remote node)"},
testVersion2: {skip: "executes locally on mongos (not sent to any remote node)"},
testVersions1And2: {skip: "executes locally on mongos (not sent to any remote node)"},
upgradeDowngradeViewlessTimeseries: {skip: "internal command"},
transitionFromDedicatedConfigServer: {skip: "not on a user database"},
transitionToDedicatedConfigServer: {skip: "not on a user database"},
unshardCollection: {skip: "does not forward command to primary shard"},
untrackUnshardedCollection: {skip: "does not forward command to primary shard"},
update: {
run: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
update: collName,
updates: [{q: {_id: 2}, u: {_id: 2}, upsert: true, multi: false}],
};
},
},
explain: {
sendsDbVersion: true,
command: function (dbName, collName) {
return {
explain: {
update: collName,
updates: [{q: {_id: 2}, u: {_id: 2}, upsert: true, multi: false}],
},
};
},
},
},
updateRole: {skip: "always targets the config server"},
updateSearchIndex: {skip: "executes locally on mongos", conditional: true},
updateUser: {skip: "always targets the config server"},
updateZoneKeyRange: {skip: "not on a user database"},
usersInfo: {skip: "always targets the config server"},
validate: {
run: {
sendsDbVersion: true,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {validate: collName};
},
},
},
validateDBMetadata: {
run: {
// validateDBMetadata is always broadcast to all shards.
sendsDbVersion: false,
explicitlyCreateCollection: true,
command: function (dbName, collName) {
return {validateDBMetadata: 1, apiParameters: {version: "1"}};
},
},
},
waitForFailPoint: {skip: "executes locally on mongos (not sent to any remote node)"},
whatsmyuri: {skip: "executes locally on mongos (not sent to any remote node)"},
},
mongod: {
_addShard: {skip: "not on a user database"},
_internalClearCollectionShardingMetadata: {skip: "internal command"},
_configsvrAbortReshardCollection: {skip: "TODO"},
_configsvrAddShard: {skip: "not on a user database"},
_configsvrAddShardToZone: {skip: "TODO"},
_configsvrBalancerCollectionStatus: {skip: "TODO"},
_configsvrBalancerStart: {skip: "TODO"},
_configsvrBalancerStatus: {skip: "TODO"},
_configsvrBalancerStop: {skip: "TODO"},
_configsvrCheckClusterMetadataConsistency: {skip: "TODO"},
_configsvrCheckMetadataConsistency: {skip: "runs on the configserver"},
_configsvrClearJumboFlag: {skip: "TODO"},
_configsvrCollMod: {skip: "TODO"},
_configsvrCommitChunkMigration: {skip: "TODO"},
_configsvrCommitChunkSplit: {skip: "TODO"},
_configsvrCommitChunksMerge: {skip: "TODO"},
_configsvrCommitMergeAllChunksOnShard: {skip: "TODO"},
_configsvrCommitMovePrimary: {skip: "TODO"},
_configsvrCommitRefineCollectionShardKey: {skip: "TODO"},
_configsvrCommitReshardCollection: {skip: "TODO"},
_configsvrCommitShardRemoval: {skip: "runs on the configserver"},
_configsvrConfigureCollectionBalancing: {skip: "TODO"},
_configsvrCreateDatabase: {skip: "TODO"},
_configsvrEnsureChunkVersionIsGreaterThan: {skip: "TODO"},
_configsvrGetHistoricalPlacement: {skip: "TODO"},
_configsvrMoveRange: {skip: "TODO"},
_configsvrRemoveChunks: {skip: "TODO"},
_configsvrRemoveShard: {skip: "TODO"},
_configsvrRemoveShardFromZone: {skip: "TODO"},
_configsvrRemoveTags: {skip: "TODO"},
_configsvrResetPlacementHistory: {skip: "TODO"},
_configsvrReshardCollection: {skip: "TODO"},
_configsvrRunRestore: {skip: "TODO"},
_configsvrSetAllowMigrations: {skip: "TODO"},
_configsvrSetClusterParameter: {skip: "TODO"},
_configsvrSetUserWriteBlockMode: {skip: "TODO"},
_configsvrShardDrainingStatus: {skip: "TODO"},
_configsvrStartShardDraining: {skip: "TODO"},
_configsvrStopShardDraining: {skip: "TODO"},
_configsvrTransitionFromDedicatedConfigServer: {skip: "TODO"},
_configsvrTransitionToDedicatedConfigServer: {skip: "TODO"},
_configsvrUpdateZoneKeyRange: {skip: "TODO"},
_dropConnectionsToMongot: {skip: "TODO"},
_dropMirrorMaestroConnections: {skip: "TODO", conditional: true},
_flushDatabaseCacheUpdates: {skip: "TODO"},
_flushDatabaseCacheUpdatesWithWriteConcern: {skip: "TODO"},
_flushReshardingStateChange: {skip: "TODO"},
_flushRoutingTableCacheUpdates: {skip: "TODO"},
_flushRoutingTableCacheUpdatesWithWriteConcern: {skip: "TODO"},
_getNextSessionMods: {skip: "TODO"},
_getUserCacheGeneration: {skip: "TODO"},
_hashBSONElement: {skip: "TODO"},
_isSelf: {skip: "TODO"},
_killOperations: {skip: "TODO"},
_mergeAuthzCollections: {skip: "TODO"},
_migrateClone: {skip: "TODO"},
_mirrorMaestroConnPoolStats: {skip: "TODO", conditional: true},
_mongotConnPoolStats: {skip: "TODO"},
_flushShardRegistry: {skip: "TODO"},
_recvChunkAbort: {skip: "TODO"},
_recvChunkCommit: {skip: "TODO"},
_recvChunkReleaseCritSec: {skip: "TODO"},
_recvChunkStart: {skip: "TODO"},
_recvChunkStatus: {skip: "TODO"},
_refreshQueryAnalyzerConfiguration: {skip: "TODO"},
_shardsvrAbortReshardCollection: {skip: "TODO"},
_shardsvrBeginMigrationBlockingOperation: {skip: "TODO"},
_shardsvrCheckCanConnectToConfigServer: {skip: "TODO"},
_shardsvrCheckMetadataConsistency: {
run: {
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {_shardsvrCheckMetadataConsistency: 1};
},
expectedFailureCode: ErrorCodes.IllegalOperation,
},
},
_shardsvrCheckMetadataConsistencyParticipant: {skip: "TODO"},
_shardsvrCleanupStructuredEncryptionData: {skip: "TODO"},
_shardsvrCloneAuthoritativeMetadata: {skip: "TODO"},
_shardsvrCloneCatalogData: {skip: "TODO"},
_shardsvrCollMod: {skip: "TODO"},
_shardsvrCollModParticipant: {skip: "TODO"},
_shardsvrCommitCreateDatabaseMetadata: {skip: "TODO"},
_shardsvrCommitDropDatabaseMetadata: {skip: "TODO"},
_shardsvrCommitReshardCollection: {skip: "TODO"},
_shardsvrCompactStructuredEncryptionData: {skip: "TODO"},
_shardsvrConvertToCapped: {skip: "TODO"},
_shardsvrConvertToCappedParticipant: {skip: "TODO"},
_shardsvrCoordinateMultiUpdate: {skip: "TODO"},
_shardsvrCreateCollection: {skip: "TODO"},
_shardsvrCreateCollectionParticipant: {skip: "TODO"},
_shardsvrDrainOngoingDDLOperations: {skip: "TODO"},
_shardsvrDropCollection: {skip: "TODO"},
_shardsvrDropCollectionIfUUIDNotMatchingWithWriteConcern: {skip: "TODO"},
_shardsvrDropCollectionParticipant: {skip: "TODO"},
_shardsvrDropDatabase: {
run: {
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {
_shardsvrDropDatabase: dbName,
writeConcern: {w: "majority"},
};
},
expectedFailureCode: ErrorCodes.IllegalOperation,
},
},
_shardsvrDropDatabaseParticipant: {skip: "TODO"},
_shardsvrDropIndexes: {skip: "TODO"},
_shardsvrDropIndexesParticipant: {skip: "TODO"},
_shardsvrEndMigrationBlockingOperation: {skip: "TODO"},
_shardsvrFetchCollMetadata: {skip: "TODO"},
_shardsvrGetStatsForBalancing: {skip: "TODO"},
_shardsvrJoinDDLCoordinators: {skip: "TODO"},
_shardsvrJoinMigrations: {skip: "TODO"},
_shardsvrMergeChunks: {skip: "TODO"},
_shardsvrMergeAllChunksOnShard: {skip: "TODO"},
_shardsvrMovePrimary: {skip: "TODO"},
_shardsvrMovePrimaryEnterCriticalSection: {skip: "TODO"},
_shardsvrMovePrimaryExitCriticalSection: {skip: "TODO"},
_shardsvrMoveRange: {skip: "TODO"},
_shardsvrNotifyShardingEvent: {skip: "TODO"},
_shardsvrParticipantBlock: {skip: "TODO"},
_shardsvrRecreateRangeDeletionTasks: {skip: "TODO"},
_shardsvrRecreateRangeDeletionTasksParticipant: {skip: "TODO"},
_shardsvrRefineCollectionShardKey: {skip: "TODO"},
_shardsvrCommitRefineCollectionShardKey: {skip: "internal command"},
_shardsvrCommitCollModCollectionMetadata: {skip: "internal command"},
_shardsvrCommitDropCollectionMetadata: {skip: "internal command"},
_shardsvrCommitCreateCollectionMetadata: {skip: "internal command"},
_shardsvrRenameCollection: {skip: "TODO"},
_shardsvrRenameCollectionParticipant: {skip: "TODO"},
_shardsvrRenameCollectionParticipantUnblock: {skip: "TODO"},
_shardsvrRenameIndexMetadata: {skip: "TODO"},
_shardsvrReshardCollection: {skip: "TODO"},
_shardsvrReshardDonorInitialize: {skip: "TODO"},
_shardsvrReshardDonorCriticalSectionStarted: {
run: {
sendsDbVersion: false,
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
_shardsvrReshardDonorCriticalSectionStarted: UUID(),
};
},
expectedFailureCode: ErrorCodes.IllegalOperation,
},
},
_shardsvrReshardDonorRecipientsFinishedCloning: {
run: {
sendsDbVersion: false,
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
_shardsvrReshardDonorRecipientsFinishedCloning: UUID(),
};
},
expectedFailureCode: ErrorCodes.IllegalOperation,
},
},
_shardsvrReshardRecipientInitialize: {skip: "TODO"},
_shardsvrReshardRecipientClone: {skip: "TODO"},
_shardsvrReshardRecipientCriticalSectionStarted: {
run: {
sendsDbVersion: false,
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
_shardsvrReshardRecipientCriticalSectionStarted: UUID(),
};
},
// When the resharding recipient state machine does not exist, we throw
// NotWritablePrimary under the assumption that the request was delayed and the
// node is no longer the primary.
expectedFailureCode: ErrorCodes.NotWritablePrimary,
},
},
_shardsvrReshardingDonorFetchFinalCollectionStats: {skip: "TODO"},
_shardsvrReshardingDonorStartChangeStreamsMonitor: {skip: "TODO"},
_shardsvrReshardingOperationTime: {skip: "TODO"},
_shardsvrResolveView: {
run: [
{
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {
_shardsvrResolveView: 1,
nss: `${dbName}.${collName}`,
databaseVersion: dbVersionAfter,
};
},
// Send to new primary with correct version - should succeed.
runOnNewPrimaryShard: true,
},
{
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {
_shardsvrResolveView: 1,
nss: `${dbName}.${collName}`,
databaseVersion: dbVersionBefore,
};
},
// Send to old primary with old version - should fail with StaleDbVersion.
runOnOldPrimaryShard: true,
expectedFailureCode: ErrorCodes.StaleDbVersion,
},
{
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {
_shardsvrResolveView: 1,
nss: `${dbName}.${collName}`,
databaseVersion: dbVersionBefore,
};
},
// Send to new primary with stale version - should fail with StaleDbVersion.
runOnNewPrimaryShard: true,
expectedFailureCode: ErrorCodes.StaleDbVersion,
},
],
},
_shardsvrRunSearchIndexCommand: {skip: "TODO"},
_shardsvrSetAllowMigrations: {skip: "TODO"},
_shardsvrSetClusterParameter: {skip: "TODO"},
_shardsvrSetUserWriteBlockMode: {skip: "TODO"},
_shardsvrSplitChunk: {
run: {
runsAgainstAdminDb: true,
command: function (dbName, collName) {
return {
_shardsvrSplitChunk: dbName + "." + collName,
keyPattern: {_id: 1},
min: {_id: MinKey},
max: {_id: MaxKey},
splitKeys: [{_id: 0}],
from: "shard0",
epoch: ObjectId(),
};
},
expectedFailureCode: ErrorCodes.StaleConfig,
},
},
_shardsvrUpgradeDowngradeViewlessTimeseries: {skip: "internal command"},
_shardsvrTimeseriesUpgradeDowngradePrepare: {skip: "internal command"},
_shardsvrTimeseriesUpgradeDowngradeCommit: {skip: "internal command"},
_shardsvrUntrackUnsplittableCollection: {skip: "TODO"},
_shardsvrValidateShardKeyCandidate: {skip: "TODO"},
_transferMods: {skip: "TODO"},
abortTransaction: {skip: "TODO"},
aggregate: {skip: "TODO"},
analyze: {skip: "TODO"},
analyzeShardKey: {skip: "TODO"},
appendOplogNote: {skip: "TODO"},
applyOps: {skip: "TODO"},
authenticate: {skip: "TODO"},
autoCompact: {skip: "TODO"},
autoSplitVector: {skip: "TODO"},
buildInfo: {skip: "TODO"},
bulkWrite: {skip: "TODO"},
checkShardingIndex: {skip: "TODO"},
cleanupOrphaned: {skip: "TODO"},
cleanupStructuredEncryptionData: {skip: "TODO"},
clearLog: {skip: "TODO"},
cloneCollectionAsCapped: {skip: "TODO"},
clusterAbortTransaction: {skip: "TODO"},
clusterAggregate: {skip: "TODO"},
clusterBulkWrite: {skip: "TODO"},
clusterCommitTransaction: {skip: "TODO"},
clusterCount: {skip: "TODO"},
clusterDelete: {skip: "TODO"},
clusterFind: {skip: "TODO"},
clusterGetMore: {skip: "TODO"},
clusterInsert: {skip: "TODO"},
clusterUpdate: {skip: "TODO"},
collMod: {skip: "TODO"},
collStats: {skip: "TODO"},
commitTransaction: {skip: "TODO"},
compact: {skip: "TODO"},
compactStructuredEncryptionData: {skip: "TODO"},
configureFailPoint: {skip: "TODO"},
configureQueryAnalyzer: {skip: "TODO"},
connPoolStats: {skip: "TODO"},
connPoolSync: {skip: "TODO"},
connectionStatus: {skip: "TODO"},
convertToCapped: {skip: "TODO"},
coordinateCommitTransaction: {skip: "TODO"},
count: {skip: "TODO"},
cpuload: {skip: "TODO"},
create: {skip: "TODO"},
createIndexes: {skip: "TODO"},
createRole: {skip: "TODO"},
createSearchIndexes: {skip: "TODO"},
createUser: {skip: "TODO"},
currentOp: {skip: "TODO"},
dataSize: {skip: "TODO"},
dbCheck: {skip: "TODO"},
dbHash: {skip: "TODO"},
dbStats: {skip: "TODO"},
delete: {skip: "TODO"},
distinct: {skip: "TODO"},
drop: {skip: "TODO"},
dropAllRolesFromDatabase: {skip: "TODO"},
dropAllUsersFromDatabase: {skip: "TODO"},
dropConnections: {skip: "TODO"},
dropDatabase: {skip: "TODO"},
dropIndexes: {skip: "TODO"},
dropRole: {skip: "TODO"},
dropSearchIndex: {skip: "TODO"},
dropUser: {skip: "TODO"},
echo: {skip: "TODO"},
endSessions: {skip: "TODO"},
eseRotateActiveKEK: {skip: "TODO", conditional: true},
explain: {skip: "TODO"},
exportCollection: {skip: "TODO", conditional: true},
features: {skip: "TODO"},
filemd5: {skip: "TODO"},
find: {skip: "TODO"},
findAndModify: {skip: "TODO"},
flushRouterConfig: {skip: "TODO"},
fsync: {skip: "TODO"},
fsyncUnlock: {skip: "TODO"},
getAuditConfig: {skip: "TODO", conditional: true},
getChangeStreamState: {skip: "TODO"}, // Removed in v8.3
getClusterParameter: {skip: "TODO"},
getCmdLineOpts: {skip: "TODO"},
getDatabaseVersion: {skip: "TODO"},
getDefaultRWConcern: {skip: "TODO"},
getDiagnosticData: {skip: "TODO"},
getESERotateActiveKEKStatus: {skip: "TODO", conditional: true},
getLog: {skip: "TODO"},
getMore: {skip: "TODO"},
getParameter: {skip: "TODO"},
getQueryableEncryptionCountInfo: {skip: "TODO"},
getShardMap: {skip: "TODO"},
getShardVersion: {skip: "TODO"},
getShardingReady: {skip: "TODO"},
getTrafficRecordingStatus: {skip: "TODO"},
godinsert: {skip: "TODO"},
grantPrivilegesToRole: {skip: "TODO"},
grantRolesToRole: {skip: "TODO"},
grantRolesToUser: {skip: "TODO"},
hello: {skip: "TODO"},
hostInfo: {skip: "TODO"},
httpClientRequest: {skip: "TODO"},
importCollection: {skip: "TODO", conditional: true},
insert: {skip: "TODO"},
internalRenameIfOptionsAndIndexesMatch: {skip: "TODO"},
invalidateUserCache: {skip: "TODO"},
isMaster: {skip: "TODO"},
killAllSessions: {skip: "TODO"},
killAllSessionsByPattern: {skip: "TODO"},
killCursors: {skip: "TODO"},
killOp: {skip: "TODO"},
killSessions: {skip: "TODO"},
listCollections: {skip: "TODO"},
listCommands: {skip: "TODO"},
listDatabases: {skip: "TODO"},
listDatabasesForAllTenants: {skip: "TODO"},
listIndexes: {skip: "TODO"},
listSearchIndexes: {skip: "TODO"},
lockInfo: {skip: "TODO"},
logApplicationMessage: {skip: "TODO", conditional: true},
logMessage: {skip: "TODO"},
logRotate: {skip: "TODO"},
logout: {skip: "TODO"},
makeSnapshot: {skip: "TODO"},
mapReduce: {skip: "TODO"},
oidcListKeys: {skip: "TODO", conditional: true},
oidcRefreshKeys: {skip: "TODO", conditional: true},
persistenceProviderProperties: {skip: "test command"},
pinHistoryReplicated: {skip: "TODO"},
ping: {skip: "TODO"},
planCacheClear: {skip: "TODO"},
planCacheClearFilters: {skip: "TODO"},
planCacheListFilters: {skip: "TODO"},
planCacheSetFilter: {skip: "TODO"},
prepareTransaction: {skip: "TODO"},
blockReplicaSetWrites: {skip: "not on a user database", conditional: true},
profile: {skip: "TODO"},
reIndex: {skip: "TODO"},
reapLogicalSessionCacheNow: {skip: "TODO"},
refreshLogicalSessionCacheNow: {skip: "TODO"},
refreshSessions: {skip: "TODO"},
releaseMemory: {skip: "TODO"},
removeQuerySettings: {skip: "TODO"},
renameCollection: {skip: "TODO"},
replSetAbortPrimaryCatchUp: {skip: "TODO"},
replSetFreeze: {skip: "TODO"},
replSetGetConfig: {skip: "TODO"},
replSetGetRBID: {skip: "TODO"},
replSetGetStatus: {skip: "TODO"},
replSetHeartbeat: {skip: "TODO"},
replSetInitiate: {skip: "TODO"},
replSetMaintenance: {skip: "TODO"},
replSetReconfig: {skip: "TODO"},
replSetRequestVotes: {skip: "TODO"},
replSetResizeOplog: {skip: "TODO"},
replSetStepDown: {skip: "TODO"},
replSetStepUp: {skip: "TODO"},
replSetSyncFrom: {skip: "TODO"},
replSetTest: {skip: "TODO"},
replSetTestEgress: {skip: "TODO"},
replSetUpdatePosition: {skip: "TODO"},
revokePrivilegesFromRole: {skip: "TODO"},
revokeRolesFromRole: {skip: "TODO"},
revokeRolesFromUser: {skip: "TODO"},
rolesInfo: {skip: "TODO"},
rotateCertificates: {skip: "TODO"},
rotateFTDC: {skip: "TODO"},
saslContinue: {skip: "TODO"},
saslStart: {skip: "TODO"},
serverStatus: {skip: "TODO"},
setAuditConfig: {skip: "TODO", conditional: true},
setChangeStreamState: {skip: "TODO"}, // Removed in v8.3
setClusterParameter: {skip: "TODO"},
setCommittedSnapshot: {skip: "TODO"},
setDefaultRWConcern: {skip: "TODO"},
setFeatureCompatibilityVersion: {skip: "TODO"},
setIndexCommitQuorum: {skip: "TODO"},
setParameter: {skip: "TODO"},
setProfilingFilterGlobally: {skip: "TODO"},
setQuerySettings: {skip: "TODO"},
setUserWriteBlockMode: {skip: "TODO"},
shardingState: {skip: "TODO"},
shutdown: {skip: "TODO"},
sleep: {skip: "TODO"},
splitChunk: {skip: "is deprecated", conditional: true},
splitVector: {skip: "TODO"},
startSession: {skip: "TODO"},
startTrafficRecording: {skip: "TODO"},
stopTrafficRecording: {skip: "TODO"},
streams_getMetrics: {skip: "TODO", conditional: true},
streams_getMoreStreamSample: {skip: "TODO", conditional: true},
streams_getStats: {skip: "TODO", conditional: true},
streams_listStreamProcessors: {skip: "TODO", conditional: true},
streams_sendEvent: {skip: "TODO", conditional: true},
streams_startStreamProcessor: {skip: "TODO", conditional: true},
streams_startStreamSample: {skip: "TODO", conditional: true},
streams_stopStreamProcessor: {skip: "TODO", conditional: true},
streams_testOnlyGetFeatureFlags: {skip: "TODO", conditional: true},
streams_testOnlyInsert: {skip: "TODO", conditional: true},
streams_updateConnection: {skip: "TODO", conditional: true},
streams_updateFeatureFlags: {skip: "TODO", conditional: true},
streams_writeCheckpoint: {skip: "TODO", conditional: true},
sysprofile: {skip: "TODO"},
testCommandFeatureFlaggedOnLatestFCV83: {skip: "internal command", conditional: true},
testDeprecation: {skip: "TODO", conditional: true},
testDeprecationInVersion2: {skip: "TODO", conditional: true},
testInternalTransactions: {skip: "TODO", conditional: true},
testRemoval: {skip: "TODO", conditional: true},
testReshardCloneCollection: {skip: "TODO", conditional: true},
testVersion2: {skip: "TODO", conditional: true},
testVersions1And2: {skip: "TODO", conditional: true},
timeseriesCatalogBucketParamsChanged: {skip: "TODO", conditional: true},
top: {skip: "TODO"},
transitionToShardedCluster: {skip: "TODO"},
update: {skip: "TODO"},
updateRole: {skip: "TODO"},
updateSearchIndex: {skip: "TODO"},
updateUser: {skip: "TODO"},
usersInfo: {skip: "TODO"},
validate: {skip: "TODO"},
validateDBMetadata: {skip: "TODO"},
voteAbortIndexBuild: {skip: "TODO"},
voteCommitImportCollection: {skip: "TODO", conditional: true},
voteCommitIndexBuild: {skip: "TODO"},
waitForFailPoint: {skip: "TODO", conditional: true},
whatsmysni: {skip: "TODO"},
whatsmyuri: {skip: "TODO"},
},
};
const st = new ShardingTest({
shards: 2,
mongos: 2,
});
// Helper function to check if authoritative database shards feature is enabled.
function isAuthoritativeShardsEnabled(conn) {
return FeatureFlagUtil.isPresentAndEnabled(conn, "AuthoritativeShardsCRUD");
}
const doTest = (connection, testCases, commandsAddedSinceLastLTS, commandsRemovedSinceLastLTS, isMongodTest) => {
const listCommandsRes = connection.adminCommand({listCommands: 1});
assert.commandWorked(listCommandsRes);
print("--------------------------------------------");
for (const command of Object.keys(listCommandsRes.commands)) {
print(command);
}
const isMultiversion = Boolean(jsTest.options().useRandomBinVersionsWithinReplicaSet);
commandsRemovedSinceLastLTS.forEach(function (cmd) {
testCases[cmd] = {
skip: "must define test coverage for latest version backwards compatibility",
};
});
(() => {
// Validate test cases for all commands.
// Ensure there is a test case for every mongos command, and that the test cases are
// well formed.
for (const command of Object.keys(listCommandsRes.commands)) {
const testCase = testCases[command];
assert(testCase !== undefined, "coverage failure: must define a test case for " + command);
validateTestCase(testCase, connection == st.s);
testCases[command].validated = true;
}
// After iterating through all the existing commands, ensure there were no additional
// test cases that did not correspond to any mongos command.
for (const key of Object.keys(testCases)) {
// We have defined real test cases for commands added since the last LTS version so
// that the test cases are exercised in the regular suites, but because these test
// cases can't run in the last stable suite, we skip processing them here to avoid
// failing the below assertion. We have defined "skip" test cases for commands
// removed since the last LTS version so the test case is defined in last stable
// suites (in which these commands still exist on the mongos), but these test cases
// won't be run in regular suites, so we skip processing them below as well.
if (commandsAddedSinceLastLTS.includes(key) || commandsRemovedSinceLastLTS.includes(key)) {
continue;
}
assert(
testCases[key].validated || testCases[key].conditional,
`you defined a test case for a command '${key}' that does not exist: ${tojson(testCases[key])}`,
);
}
})();
// Set of commands that are supported on all shards (used only for mongod tests).
const commandsSupportedOnAllMongod = (() => {
if (!isMongodTest) {
return new Set();
}
const shards = [st.shard0, st.shard1];
// Initialize the intersection with the first shard's commands
const firstRes = shards[0].getDB("admin").runCommand({listCommands: 1});
assert.commandWorked(firstRes);
const validCommands = new Set(Object.keys(firstRes.commands));
// Filter against remaining shards
for (let i = 1; i < shards.length; i++) {
const res = shards[i].getDB("admin").runCommand({listCommands: 1});
assert.commandWorked(res);
for (const cmd of validCommands) {
if (!res.commands.hasOwnProperty(cmd)) {
validCommands.delete(cmd);
}
}
}
return validCommands;
})();
(() => {
// Test that commands that send databaseVersion are subjected to the databaseVersion
// check when the primary shard for the database has moved and the database no longer
// exists on the old primary shard (because the database only contained unsharded
// collections; this is in anticipation of SERVER-43925).
const dbName = getNewDbName();
const collName = "foo";
// Create the database by creating a collection in it.
assert.commandWorked(st.s0.getDB(dbName).createCollection("dummy"));
for (const command of Object.keys(listCommandsRes.commands)) {
const testCase = testCases[command];
if (testCase.skip || (isMultiversion && testCase.skipMultiversion)) {
print("skipping " + command + ": " + testCase.skip);
continue;
}
if (isMultiversion && isMongodTest && !commandsSupportedOnAllMongod.has(command)) {
assert(
commandsAddedToMongodSinceLastLTS.includes(command),
"did not expect " + command + " to not be supported on all shards",
);
print("skipping " + command + ": not supported on all shards");
continue;
}
for (const test of toArray(testCase.run)) {
testCommandAfterMovePrimary(test, connection, st, dbName, collName);
}
if (testCase.explain) {
for (const test of toArray(testCase.explain)) {
testCommandAfterMovePrimary(test, connection, st, dbName, collName);
}
}
}
})();
(() => {
// Test that commands that send databaseVersion are subjected to the databaseVersion
// check when the primary shard for the database has moved, but the database still
// exists on the old primary shard (because the old primary shard owns chunks for
// sharded collections in the database).
const dbName = getNewDbName();
const collName = "foo";
const shardedCollName = "pinnedShardedCollWithChunksOnBothShards";
// Create a sharded collection with data on both shards so that the database does not
// get dropped on the old primary shard after movePrimary.
const shardedCollNs = dbName + "." + shardedCollName;
assert.commandWorked(st.s0.adminCommand({enableSharding: dbName}));
assert.commandWorked(st.s0.adminCommand({addShardToZone: st.shard0.shardName, zone: "x < 0"}));
assert.commandWorked(st.s0.adminCommand({addShardToZone: st.shard1.shardName, zone: "x >= 0"}));
assert.commandWorked(
st.s0.adminCommand({updateZoneKeyRange: shardedCollNs, min: {x: MinKey}, max: {x: 0}, zone: "x < 0"}),
);
assert.commandWorked(
st.s0.adminCommand({updateZoneKeyRange: shardedCollNs, min: {x: 0}, max: {x: MaxKey}, zone: "x >= 0"}),
);
assert.commandWorked(st.s0.getDB("admin").admin.runCommand({shardCollection: shardedCollNs, key: {"x": 1}}));
assert(containsCollection(st.shard0, dbName, shardedCollName));
assert(containsCollection(st.shard1, dbName, shardedCollName));
for (const command of Object.keys(listCommandsRes.commands)) {
const testCase = testCases[command];
if (testCase.skip || (isMultiversion && testCase.skipMultiversion)) {
print("skipping " + command + ": " + testCase.skip);
continue;
}
if (isMultiversion && isMongodTest && !commandsSupportedOnAllMongod.has(command)) {
assert(
commandsAddedToMongodSinceLastLTS.includes(command),
"did not expect " + command + " to not be supported on all shards",
);
print("skipping " + command + ": not supported on all shards");
continue;
}
for (const test of toArray(testCase.run)) {
testCommandAfterMovePrimary(test, connection, st, dbName, collName);
}
if (testCase.explain) {
for (const test of toArray(testCase.explain)) {
testCommandAfterMovePrimary(test, connection, st, dbName, collName);
}
}
}
})();
(() => {
// Test that commands that send databaseVersion are subjected to the databaseVersion
// check when the database has been dropped and recreated with a different primary
// shard.
for (const command of Object.keys(listCommandsRes.commands)) {
const testCase = testCases[command];
if (testCase.skip || (isMultiversion && testCase.skipMultiversion)) {
print("skipping " + command + ": " + testCase.skip);
continue;
}
if (isMultiversion && isMongodTest && !commandsSupportedOnAllMongod.has(command)) {
assert(
commandsAddedToMongodSinceLastLTS.includes(command),
"did not expect " + command + " to not be supported on all shards",
);
print("skipping " + command + ": not supported on all shards");
continue;
}
for (const test of toArray(testCase.run)) {
testCommandAfterDropRecreateDatabase(test, connection, st);
}
if (testCase.explain) {
for (const test of toArray(testCase.explain)) {
testCommandAfterDropRecreateDatabase(test, connection, st);
}
}
}
})();
};
doTest(
st.s,
allTestCases.mongos,
commandsAddedToMongosSinceLastLTS,
commandsRemovedFromMongosSinceLastLTS,
false /* isMongodTest */,
);
doTest(
st.rs0.getPrimary(),
allTestCases.mongod,
commandsAddedToMongodSinceLastLTS,
commandsRemovedFromMongodSinceLastLTS,
true /* isMongodTest */,
);
st.stop();