mongo/jstests/sharding/database_versioning_all_com...

1472 lines
67 KiB
JavaScript

/**
* Specifies for each command whether it is expected to send a databaseVersion, and verifies that
* the commands match the specification.
*
* 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.
*/
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),
);
}
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 (!FeatureFlagUtil.isPresentAndEnabled(primaryShardBefore, "ShardAuthoritativeDbMetadataCRUD")) {
assert.commandWorked(primaryShardBefore.adminCommand({_flushDatabaseCacheUpdates: dbName}));
}
if (!FeatureFlagUtil.isPresentAndEnabled(primaryShardAfter, "ShardAuthoritativeDbMetadataCRUD")) {
assert.commandWorked(primaryShardAfter.adminCommand({_flushDatabaseCacheUpdates: dbName}));
}
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionBefore);
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, both old and new primary shards should have cleared the dbVersion.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
assertMatchingDatabaseVersion(primaryShardAfter, dbName, {});
const command = testCase.command(dbName, collName, dbVersionBefore, dbVersionAfter);
jsTest.log(
"testing command " +
tojson(command) +
" after movePrimary; primary shard before: " +
primaryShardBefore +
", database version before: " +
tojson(dbVersionBefore) +
", primary shard after: " +
primaryShardAfter,
);
// Run the test case's command.
const res = connection.getDB(testCase.runsAgainstAdminDb ? "admin" : dbName).runCommand(command);
if (testCase.expectedFailureCode) {
assert.commandFailedWithCode(res, testCase.expectedFailureCode);
} else {
assert.commandWorked(res);
}
// 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, all nodes should now know the new
// dbVersion:
// 1. The mongos should have sent the stale dbVersion to the old primary shard
// 2. The old primary shard should have returned StaleDbVersion and refreshed
// 3. Which should have caused the mongos to refresh and retry against the new primary
// shard
// 4. The new primary shard should have returned StaleDbVersion and refreshed
// 5. Which should have caused the mongos to refresh and retry again, this time
// succeeding.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionAfter);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionAfter);
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
// If the command does not participate in database versioning:
// 1. The mongos should have targeted the old primary shard but not attached a dbVersion
// 2. The old primary shard should have returned an ok response
// 3. Both old and new primary shards should have cleared the dbVersion
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
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);
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.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
const command = testCase.command(dbName, collName, dbVersionBefore, dbVersionAfter);
jsTest.log(
"testing command " +
tojson(command) +
" after drop/recreate database; primary shard before: " +
primaryShardBefore +
", database version before: " +
tojson(dbVersionBefore) +
", primary shard after: " +
primaryShardAfter,
);
// Run the test case's command.
const res = connection.getDB(testCase.runsAgainstAdminDb ? "admin" : dbName).runCommand(command);
if (testCase.expectedFailureCode) {
assert.commandFailedWithCode(res, testCase.expectedFailureCode);
} else {
assert.commandWorked(res);
}
// 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 all nodes should now know the new
// dbVersion:
// 1. The mongos should have sent the stale dbVersion to the old primary shard
// 2. The old primary shard should have returned StaleDbVersion and refreshed
// 3. Which should have caused the mongos to refresh and retry against the new primary
// shard
// 4. The new primary shard should have returned StaleDbVersion and refreshed
// 5. Which should have caused the mongos to refresh and retry again, this time
// succeeding.
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionAfter);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, dbVersionAfter);
assertMatchingDatabaseVersion(primaryShardAfter, dbName, dbVersionAfter);
} else {
// If the command does not participate in database versioning, none of the nodes' view
// of the dbVersion should have changed:
// 1. The mongos should have targeted the old primary shard but not attached a dbVersion
// 2. The old primary shard should have returned an ok response
assertMatchingDatabaseVersion(st.s0, dbName, dbVersionBefore);
assertMatchingDatabaseVersion(primaryShardBefore, dbName, {});
}
}
// 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},
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},
};
},
},
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,
},
changePrimary: {skip: "reads primary shard from sharding catalog with readConcern: local"},
checkMetadataConsistency: {
run: {
sendsDbVersion: true,
runsAgainstAdminDb: false,
command: function (dbName, collName) {
return {checkMetadataConsistency: 1};
},
},
},
cleanupReshardCollection: {skip: "always targets the config server"},
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}};
},
},
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"};
},
},
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}};
},
},
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};
},
},
},
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};
},
},
},
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"},
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(),
);
},
},
},
repairShardedCollectionChunksHistory: {skip: "always targets the config server"},
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: {skip: "does not forward command to primary shard"},
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)"},
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"},
_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"},
_configsvrCleanupReshardCollection: {skip: "TODO"},
_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"},
_configsvrRepairShardedCollectionChunksHistory: {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"},
_recvChunkAbort: {skip: "TODO"},
_recvChunkCommit: {skip: "TODO"},
_recvChunkReleaseCritSec: {skip: "TODO"},
_recvChunkStart: {skip: "TODO"},
_recvChunkStatus: {skip: "TODO"},
_refreshQueryAnalyzerConfiguration: {skip: "TODO"},
_shardsvrAbortReshardCollection: {skip: "TODO"},
_shardsvrBeginMigrationBlockingOperation: {skip: "TODO"},
_shardsvrChangePrimary: {skip: "TODO"},
_shardsvrCheckCanConnectToConfigServer: {skip: "TODO"},
_shardsvrCheckMetadataConsistency: {
run: {
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {_shardsvrCheckMetadataConsistency: 1};
},
expectedFailureCode: ErrorCodes.IllegalOperation,
},
},
_shardsvrCheckMetadataConsistencyParticipant: {skip: "TODO"},
_shardsvrCleanupReshardCollection: {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"},
_shardsvrRefineCollectionShardKey: {skip: "TODO"},
_shardsvrRenameCollection: {skip: "TODO"},
_shardsvrRenameCollectionParticipant: {skip: "TODO"},
_shardsvrRenameCollectionParticipantUnblock: {skip: "TODO"},
_shardsvrRenameIndexMetadata: {skip: "TODO"},
_shardsvrReshardCollection: {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,
};
},
},
{
runsAgainstAdminDb: false,
command: function (dbName, collName, dbVersionBefore, dbVersionAfter) {
return {
_shardsvrResolveView: 1,
nss: `${dbName}.${collName}`,
databaseVersion: dbVersionBefore,
};
},
expectedFailureCode: ErrorCodes.StaleDbVersion,
},
],
},
_shardsvrRunSearchIndexCommand: {skip: "TODO"},
_shardsvrSetAllowMigrations: {skip: "TODO"},
_shardsvrSetClusterParameter: {skip: "TODO"},
_shardsvrSetUserWriteBlockMode: {skip: "TODO"},
_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},
pinHistoryReplicated: {skip: "TODO"},
ping: {skip: "TODO"},
planCacheClear: {skip: "TODO"},
planCacheClearFilters: {skip: "TODO"},
planCacheListFilters: {skip: "TODO"},
planCacheSetFilter: {skip: "TODO"},
prepareTransaction: {skip: "TODO"},
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: "TODO"},
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"},
},
};
// TODO (SERVER-101777): This test makes a lot of assumptions about database versions stored in
// shards that are not the primary shard. Hence we turn off all shardAuthoritative feature flags.
const shardOptions = (() => {
if (Boolean(jsTest.options().useRandomBinVersionsWithinReplicaSet) || Boolean(TestData.multiversionBinVersion)) {
return {};
}
return {
setParameter: {
featureFlagShardAuthoritativeDbMetadataDDL: false,
featureFlagShardAuthoritativeDbMetadataCRUD: false,
featureFlagShardAuthoritativeCollMetadata: false,
},
};
})();
const st = new ShardingTest({
shards: 2,
mongos: 2,
other: {
configOptions: shardOptions,
rsOptions: shardOptions,
},
});
const doTest = (connection, testCases, commandsAddedSinceLastLTS, commandsRemovedSinceLastLTS) => {
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])}`,
);
}
})();
(() => {
// 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;
}
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;
}
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;
}
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);
doTest(
st.rs0.getPrimary(),
allTestCases.mongod,
commandsAddedToMongodSinceLastLTS,
commandsRemovedFromMongodSinceLastLTS,
);
st.stop();