summaryrefslogtreecommitdiff
path: root/jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js
diff options
context:
space:
mode:
Diffstat (limited to 'jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js')
-rw-r--r--jstests/multiVersion/targetedTestsLastLtsFeatures/query_stats_upgrade_downgrade.js272
1 files changed, 272 insertions, 0 deletions
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