summaryrefslogtreecommitdiff
path: root/jstests/multiVersion
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2025-02-18 17:02:53 -0300
commit959575a5ca598bf5f37fb5cebe7ed1d80d3d71f7 (patch)
treeacc8d60aedb12b70048e676e8a7349deb0010db8 /jstests/multiVersion
parent76588293975fc059cf076779e4283e6ffaf8afff (diff)
New upstream version 6.0.20upstream
Diffstat (limited to 'jstests/multiVersion')
-rw-r--r--jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js56
-rw-r--r--jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js13
-rw-r--r--jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js4
-rw-r--r--jstests/multiVersion/prepare_unique_fcv_check.js48
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js31
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js12
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js16
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js272
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js4
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js4
10 files changed, 449 insertions, 11 deletions
diff --git a/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js b/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js
new file mode 100644
index 00000000000..1e61d5280fc
--- /dev/null
+++ b/jstests/multiVersion/genericBinVersion/query_stats_key_hash_version_consistency.js
@@ -0,0 +1,56 @@
+/**
+ * Tests that query stats key hashes are consistent across versions.
+ * @tags: [requires_fcv_60]
+ */
+(function() {
+'use strict';
+
+load("jstests/multiVersion/libs/multi_rs.js");
+load("jstests/libs/query_stats_utils.js"); // For getQueryStatsFindCmd and getQueryStatsKeyHashes.
+
+// TODO SERVER-87729 Start from the previous version.
+const rst = new ReplSetTest(
+ {nodes: {n1: {binVersion: "latest"}, n2: {binVersion: "latest"}, n3: {binVersion: "latest"}}});
+
+// Turn on the collecting of query stats metrics.
+rst.startSet({setParameter: {internalQueryStatsRateLimit: -1}});
+rst.initiate();
+
+let conn = rst.getPrimary();
+const collName = jsTestName();
+let coll = conn.getDB("test")[collName];
+coll.drop();
+coll.insert({x: 5});
+
+// Run a few unique queries so that they generate different query stats entries.
+function runQueries() {
+ coll.find({x: 5}).toArray();
+ coll.find({y: 5}).toArray();
+ coll.find({y: 5}).sort({x: -1}).toArray();
+ coll.find({y: 5}).maxTimeMS(123).toArray();
+}
+
+// First, collect and save query stats entries on the older version.
+runQueries();
+const preUpgradeEntries = getQueryStatsFindCmd(conn, {collName, transformIdentifiers: false});
+assert.eq(preUpgradeEntries.length, 4, tojson(preUpgradeEntries));
+const preUpgradeKeyHashes = getQueryStatsKeyHashes(preUpgradeEntries);
+
+// Upgrade to the latest.
+rst.upgradeSet({binVersion: 'latest'});
+conn = rst.getPrimary();
+coll = conn.getDB("test")[collName];
+
+// Run the same queries again and check that we got the same query stats key hash values as we did
+// on the old version.
+runQueries();
+const postUpgradeEntries = getQueryStatsFindCmd(conn, {collName, transformIdentifiers: false});
+assert.eq(postUpgradeEntries.length, 4, tojson(postUpgradeEntries));
+const postUpgradeKeyHashes = getQueryStatsKeyHashes(postUpgradeEntries);
+assert.sameMembers(postUpgradeKeyHashes,
+ preUpgradeKeyHashes,
+ `preUpgradeEntries = ${tojson(preUpgradeEntries)}, postUpgradeEntries = ${
+ tojson(postUpgradeEntries)}`);
+
+rst.stopSet();
+})(); \ No newline at end of file
diff --git a/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js b/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
index c49422423c4..b9a9405c182 100644
--- a/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
+++ b/jstests/multiVersion/genericBinVersion/remove_invalid_index_options.js
@@ -44,10 +44,15 @@ fpSecondary.off();
// Verify that the primary (latest) and secondary (last-lts) detect invalid index options.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 2);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid);
+// TODO (SERVER-87985): Enable assertions.
+// assert(validateRes.valid);
+// assert.eq(validateRes.errors.length, 0);
+// assert.eq(validateRes.warnings.length, 2);
// Use collMod to remove the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -64,9 +69,13 @@ checkLog.containsJson(secondary, 23878, {fieldName: "xyz"});
// Verify that the index no longer has invalid index options.
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 0);
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
assert(validateRes.valid);
+assert.eq(validateRes.errors.length, 0);
+assert.eq(validateRes.warnings.length, 0);
rst.stopSet();
})();
diff --git a/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js b/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
index 4e94668a46f..85943e6c9d1 100644
--- a/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
+++ b/jstests/multiVersion/genericBinVersion/timeseries_collection_mixed_type.js
@@ -17,7 +17,9 @@ const timeFieldName = "time";
* one bucket was created.
*/
function runTest(docs, query, results, path, bounds) {
- const oldVersion = "last-lts";
+ // Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+ // to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+ const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion},
diff --git a/jstests/multiVersion/prepare_unique_fcv_check.js b/jstests/multiVersion/prepare_unique_fcv_check.js
new file mode 100644
index 00000000000..7cf27162d64
--- /dev/null
+++ b/jstests/multiVersion/prepare_unique_fcv_check.js
@@ -0,0 +1,48 @@
+/* Test that an index that contains prepareUnique cannot be created when
+ * featureFlagCollModIndexUnique is not enabled.
+ *
+ * @tags: [requires_persistence]
+ */
+(function() {
+"use strict";
+
+const mongod = MongoRunner.runMongod();
+assert.neq(null, mongod, "mongod was unable to start up");
+const db = mongod.getDB("test");
+const admin = db.getSiblingDB("admin");
+const coll = db.test;
+try {
+ checkFCV(admin, "6.0");
+} catch (e) {
+ jsTestLog("Expecting FCV 6.0: " + tojson(e));
+ quit();
+}
+
+// createIndex with prepareUnique should work by default.
+assert.commandWorked(db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]}));
+// coll should be created implicitly.
+assert(Array.contains(db.getCollectionNames(), coll.getName()));
+
+// Downgrade FCV
+assert.commandWorked(coll.dropIndex({a: 1}));
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+// Now createIndex with prepareUnique:true should fail on an existing collection.
+let res = db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]});
+assert.commandFailedWithCode(res, ErrorCodes.InvalidOptions);
+
+// createIndex with prepareUnique:true should also fail on a new collection.
+assert(coll.drop());
+res = db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]});
+assert.commandFailedWithCode(res, ErrorCodes.InvalidOptions);
+
+// Upgrade FCV and createIndex with prepareUnique should now work.
+assert.commandWorked(db.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+assert.commandWorked(db.runCommand(
+ {createIndexes: coll.getName(), indexes: [{key: {a: 1}, name: 'a_1', prepareUnique: true}]}));
+
+MongoRunner.stopMongod(mongod);
+})();
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
index e59bc2e106a..3b183f18bef 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/change_streams_split_event_v1_v2_tokens.js
@@ -20,7 +20,11 @@ const st = new ShardingTest({
rsOptions: {
binVersion: "last-lts",
},
- rs: {nodes: 2},
+ rs: {
+ nodes: 2,
+ // Reserving enough of oplog space to accommodate 4 nearly 16MB-large changes.
+ oplogSize: 16 * 5
+ }
}
});
@@ -97,7 +101,8 @@ assert.commandWorked(
st.s.adminCommand({refineCollectionShardKey: testColl.getFullName(), key: {shard: 1, _id: 1}}));
// Produces no events on v5.0.
-assert.commandWorked(st.s.adminCommand({reshardCollection: testColl.getFullName(), key: {_id: 1}}));
+assert.commandWorked(st.s.adminCommand(
+ {reshardCollection: testColl.getFullName(), key: {_id: 1}, numInitialChunks: 1}));
// Produces no events on v5.0.
assert.commandWorked(testColl.dropIndex({largeField: 1}));
@@ -118,6 +123,28 @@ expectedEvents.push({operationType: "dropDatabase"},
{operationType: "invalidate"},
{operationType: "dropDatabase"});
+// Leave only the last of the events with identical resume tokens, because the previous events will
+// be skipped when resuming from such a token.
+// TODO SERVER-90266: Remove this workaround when no longer needed.
+{
+ const csCursor = testDB.watch([], {startAfter: testStartV1HWMToken});
+
+ // The 'drop' and 'rename' events coming from different shards are likely to get identical
+ // resume tokens in v5.0.
+ for (let prevEvent = csCursor.next(), nextEvent; csCursor.hasNext(); prevEvent = nextEvent) {
+ nextEvent = csCursor.next();
+ if (bsonWoCompare(nextEvent._id, prevEvent._id) === 0) {
+ // If two or more consecutive events have identical resume tokens, remove all but the
+ // last from the expected events.
+ expectedEvents.splice(expectedEvents.findIndex(
+ (event) => (event.operationType === prevEvent.operationType)),
+ 1);
+ }
+ }
+
+ csCursor.close();
+}
+
// Helper function to assert on the given event fields.
function assertEventMatches(event, expectedEvent, errorMsg) {
for (const k in expectedEvent) {
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
index 5844b6bfec3..a18683b2956 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/fix_invalid_index_options.js
@@ -45,10 +45,14 @@ secondaryDB = secondary.getDB(dbName);
// Verify that the primary and secondary in 6.0 detect invalid index options.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
// Use collMod to fix the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -62,9 +66,13 @@ assert.commandWorked(primaryDB.runCommand({listIndexes: collName}));
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
rst.stopSet();
})();
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
index 51c5d5b03e7..c4c23061617 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/invalid_index_options.js
@@ -59,13 +59,19 @@ const secondaryDB2 = secondary2.getDB(dbName);
// Verify that the existing nodes detect invalid index options, but the new node has the repaired
// index spec.
let validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB1.runCommand({validate: collName}));
-assert(!validateRes.valid, "validate should fail: " + tojson(validateRes));
+assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 1, "validate should warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB2.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
// Use collMod to fix the invalid index options in the collection.
assert.commandWorked(primaryDB.runCommand({collMod: collName}));
@@ -79,12 +85,18 @@ assert.commandWorked(primaryDB.runCommand({listIndexes: collName}));
validateRes = assert.commandWorked(primaryDB.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB1.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
validateRes = assert.commandWorked(secondaryDB2.runCommand({validate: collName}));
assert(validateRes.valid, "validate should succeed: " + tojson(validateRes));
+assert.eq(validateRes.errors.length, 0, "validate should not error: " + tojson(validateRes));
+assert.eq(validateRes.warnings.length, 0, "validate should not warn: " + tojson(validateRes));
rst.stopSet();
})(); \ No newline at end of file
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js
new file mode 100644
index 00000000000..20ff7add9cd
--- /dev/null
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js
@@ -0,0 +1,272 @@
+/**
+ * Verifies that $queryStats operates correctly when upgrading and downgrading.
+ */
+
+load("jstests/multiVersion/libs/multi_rs.js");
+load("jstests/multiVersion/libs/multi_cluster.js");
+load("jstests/libs/collection_drop_recreate.js");
+load("jstests/libs/query_stats_utils.js");
+
+(function() {
+"use strict";
+
+const lastLTSVersion = "last-lts";
+
+class UpgradeDowngradeTestFixture {
+ constructor() {
+ this.collectionName = "coll";
+ }
+
+ getTestDB() {
+ return this.rst.getPrimary().getDB(jsTestName());
+ }
+
+ createAndPopulateTestCollection() {
+ let testDB = this.getTestDB();
+ let coll = assertDropAndRecreateCollection(testDB, "coll");
+ assert.commandWorked(coll.insertMany([{x: 0}, {x: 1}, {x: 2}]));
+ }
+
+ setup() {
+ jsTestLog("Starting ReplicaSet Upgrade/Downgrade Test!");
+
+ this.rst = new ReplSetTest({
+ name: jsTestName(),
+ nodes: [{binVersion: lastLTSVersion}, {binVersion: lastLTSVersion}]
+ });
+ this.rst.startSet();
+ this.rst.initiate();
+ this.createAndPopulateTestCollection();
+ }
+
+ teardown() {
+ jsTestLog("Teardown ReplicaSet Upgrade/Downgrade Test!");
+
+ this.rst.stopSet();
+ }
+
+ getTestCollection() {
+ return this.getTestDB().getCollection(this.collectionName);
+ }
+
+ adminCommand(command) {
+ return this.rst.getPrimary().getDB("admin").runCommand(command);
+ }
+
+ upgradeBinaries() {
+ this.rst.upgradeSet({binVersion: "latest"});
+ }
+
+ upgradeFCV() {
+ assert.commandWorked(this.adminCommand({setFeatureCompatibilityVersion: latestFCV}));
+ }
+
+ downgradeFCV() {
+ // Downgrade FCV (without restarting) and check that $queryStats returns an error.
+ assert.commandWorked(this.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+ }
+
+ testQueryStatsParam(expectedResult) {
+ if (expectedResult === true) {
+ assert.commandWorked(
+ this.adminCommand({setParameter: 1, internalQueryStatsRateLimit: -1}));
+ } else {
+ // Check that $queryStats related parameter does not work.
+ assert.commandFailed(
+ this.adminCommand({setParameter: 1, internalQueryStatsRateLimit: -1}));
+ }
+ }
+
+ testQueryStatsCommandFailure() {
+ assert.commandFailedWithCode(
+ this.adminCommand({aggregate: 1, pipeline: [{$queryStats: {}}], cursor: {}}),
+ [ErrorCodes.QueryFeatureNotAllowed, 40324]);
+ }
+
+ isShardedCluster() {
+ return false;
+ }
+
+ verifyQueryStatsOutput({expectedNShapes}) {
+ const queryStats = getQueryStats(this, {collName: this.collectionName});
+ assert.eq(expectedNShapes, queryStats.length, queryStats);
+ verifyMetrics(queryStats);
+ }
+}
+
+class ShardedClusterUpgradeDowngradeTestFixture extends UpgradeDowngradeTestFixture {
+ setup() {
+ jsTestLog("Starting Sharded Upgrade/Downgrade Test!");
+ this.shardedTest = new ShardingTest({
+ name: jsTestName(),
+ shards: 1,
+ mongos: 1,
+ config: 1,
+ rs: {nodes: [{binVersion: lastLTSVersion}, {binVersion: lastLTSVersion}]},
+ mongosOptions: {binVersion: lastLTSVersion},
+ });
+ this.createAndPopulateTestCollection();
+ }
+
+ isShardedCluster() {
+ return true;
+ }
+
+ adminCommand(command) {
+ return this.shardedTest.s.adminCommand(command);
+ }
+
+ getTestDB() {
+ return this.shardedTest.s.getDB(jsTestName());
+ }
+
+ upgradeBinaries() {
+ this.shardedTest.upgradeCluster('latest');
+ }
+
+ teardown() {
+ jsTestLog("Teardown ReplicaSet Upgrade/Downgrade Test!");
+ this.shardedTest.stop();
+ }
+}
+
+function runTest(fixture) {
+ // 0. Initialize the fixture, we begin with a binary version that doesn't support queryStats.
+ fixture.setup();
+
+ // 1. Test that queryStats related features don't work in the base binary.
+ // 1.a. Verify queryStats is disabled by checking that setting queryStats related parameters and
+ // running the $queryStats stage both fail.
+ fixture.testQueryStatsParam(false);
+ fixture.testQueryStatsCommandFailure();
+
+ // 1.b. Run some queries while running base binary. We don't expect these queries to be
+ // collected by queryStats.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+
+ // 2. Upgrade both the binaries and FCV. After the upgrade we expect query stats features
+ // to work. Further, we verify that the previously executed queries were not collected by
+ // checking the results from the $queryStats stage.
+ fixture.upgradeBinaries();
+ fixture.upgradeFCV();
+
+ // 2.a. Verify that queryStats parameters can be set after the upgrade, and that previously
+ // executed queries were not collected.
+ fixture.testQueryStatsParam(true);
+ fixture.verifyQueryStatsOutput({expectedNShapes: 0});
+
+ // 2.b. Execute two new queries (i.e new query shapes) and check that they are collected.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}, {$sort: {x: -1}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}, {noCursorTimeout: true}).toArray();
+ assert.eq(1, res.length, res);
+
+ fixture.verifyQueryStatsOutput({
+ expectedNShapes: 2 /* 1 each for the above. $queryStats is not included because we
+ filter on the collection name. */
+ });
+ }
+
+ // 3. Downgrade FCV (without restarting). Without restarting the server, we expect the
+ // queryStatsStore to keep existing entries, but to not collect any more statistics while an FCV
+ // that doesn't support queryStats is in place.
+ fixture.downgradeFCV();
+
+ // 3.a. Run additional queries (new query shapes) after the downgrade.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+
+ // 3.b. If we are testing a sharded cluster, we don't expect queryStats to be disabled after the
+ // FCV downgrade. This is because in a sharded cluster, query stats resides on mongos, and
+ // mongos doesn't have a concept of its own in memory FCV settings. When a sharded cluster has
+ // its FCV downgraded, it forwards the downgrade request to the shards and the config
+ // servers. However, the router itself bases its FCV on its binaries. In our case, once we
+ // upgrade the binary on the mongos, we can no longer downgrade the FCV to "disable" queryStats.
+ // As a result, in the sharded scenario we expect the two queries run after the downgrade to
+ // have been collected by query stats.
+ if (fixture.isShardedCluster()) {
+ fixture.verifyQueryStatsOutput({
+ expectedNShapes: 4 /* 2 from the previous queries + the two additional ones captured
+ after the downgrade. */
+ });
+ fixture.teardown();
+ return;
+ }
+
+ // 3.c. After the FCV downgrade (i.e FCV v5.0), running $queryStats should return an error.
+ fixture.testQueryStatsCommandFailure();
+
+ // 3.d. Upgrade the FCV without restart. QueryStatsStore should not have been cleared. Previous
+ // stats collected should be returned. The queries made during the downgrade should not
+ // have been collected. Note that getQueryStats() uses the same query to collect the statistics,
+ // so running $queryStats doesn't result in additional entries.
+ fixture.upgradeFCV();
+ fixture.verifyQueryStatsOutput({expectedNShapes: 2});
+
+ // 4. Test query stats during a failed FCV downgrade. During the failed FCV downgrade, the FCV
+ // reverts back to the lastLTSFCV which doesn't support queryStats.
+ jsTestLog("Turning the failpoint on.");
+ assert.commandWorked(
+ fixture.adminCommand({configureFailPoint: 'failDowngrading', mode: "alwaysOn"}));
+
+ assert.commandFailedWithCode(fixture.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}),
+ 549181);
+
+ // 4.a. Current FCV is lower than the FCV necessary (7.2) for queryStats to run. These queries
+ // should not be collected.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}]).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}).toArray();
+ assert.eq(1, res.length, res);
+ }
+ // 4.b. Running $queryStats should return an error.
+ fixture.testQueryStatsCommandFailure(ErrorCodes.QueryFeatureNotAllowed);
+
+ // 4.c. Complete the downgrade, then successfully upgrade FCV. Check that the queries run during
+ // the failed downgrade were not collected.
+ assert.commandWorked(
+ fixture.adminCommand({configureFailPoint: 'failDowngrading', mode: "off"}));
+ assert.commandWorked(fixture.adminCommand({setFeatureCompatibilityVersion: lastLTSFCV}));
+
+ fixture.upgradeFCV();
+ fixture.verifyQueryStatsOutput({expectedNShapes: 2});
+
+ // 4.d. Execute two new queries (new query shapes), these should result in new entries.
+ {
+ let coll = fixture.getTestCollection();
+ let res = coll.aggregate([{$match: {x: 2}}], {allowDiskUse: false}).toArray();
+ assert.eq(1, res.length, res);
+
+ res = coll.find({x: 2}, {allowPartialResults: true}).toArray();
+ assert.eq(1, res.length, res);
+
+ fixture.verifyQueryStatsOutput({expectedNShapes: 4});
+ }
+
+ fixture.teardown();
+}
+
+// Perform Upgrade/Downgrade test on replica set.
+runTest(new UpgradeDowngradeTestFixture());
+// Perform Upgrade/Downgrade test on sharded cluster.
+runTest(new ShardedClusterUpgradeDowngradeTestFixture());
+})(); \ No newline at end of file
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
index 7575c514c20..b66de0c43f0 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/timeseries_collection_mixed_schema_index_build_stepdown.js
@@ -13,7 +13,9 @@ load("jstests/libs/fail_point_util.js");
load("jstests/multiVersion/libs/multi_rs.js");
load('jstests/noPassthrough/libs/index_build.js');
-const oldVersion = "last-lts";
+// Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+// to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion}
diff --git a/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js b/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
index e714a38d698..d2fc1d83f3c 100644
--- a/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
+++ b/jstests/multiVersion/targetedTestsLastLtsFeatures/upgrade_downgrade_timeseries_collection_from_last_lts.js
@@ -13,7 +13,9 @@
load("jstests/core/timeseries/libs/timeseries.js");
load("jstests/multiVersion/libs/multi_rs.js");
-const oldVersion = "last-lts";
+// Since v5.0 no longer supports writing mixed schema buckets as of 5.0.29, pin the version
+// to 5.0.28 to retain coverage as v5.0 still supports the presence of mixed schema data.
+const oldVersion = "5.0.28";
const nodes = {
n1: {binVersion: oldVersion},
n2: {binVersion: oldVersion}