173 lines
6.0 KiB
JavaScript
173 lines
6.0 KiB
JavaScript
/**
|
|
* Tests for dummy and experimental aggregation rewrite rules.
|
|
*
|
|
* @tags: [
|
|
* ]
|
|
*/
|
|
|
|
import {FeatureFlagUtil} from "jstests/libs/feature_flag_util.js";
|
|
import {FixtureHelpers} from "jstests/libs/fixture_helpers.js";
|
|
import {isAggregationPlan} from "jstests/libs/query/analyze_plan.js";
|
|
import {setParameterOnAllNonConfigNodes} from "jstests/noPassthrough/libs/server_parameter_helpers.js";
|
|
import {configureFailPointForAllShardsAndMongos} from "jstests/libs/fail_point_util.js";
|
|
|
|
// The test sets a failpoint on a specific mongos and expects subsequent commands to hit that same mongos.
|
|
// In case of multiple mongos, disable random dispatching of command by enforcing pinToSingleMongos and route against a single mongos.
|
|
TestData.pinToSingleMongos = true;
|
|
|
|
function setServerParameter(knob, value) {
|
|
setParameterOnAllNonConfigNodes(db.getMongo(), knob, value);
|
|
}
|
|
|
|
if (
|
|
!FeatureFlagUtil.isPresentAndEnabled(db, "featureFlagEnableTestingAggregateRewriteRules") ||
|
|
!FeatureFlagUtil.isPresentAndEnabled(db, "featureFlagPathArrayness")
|
|
) {
|
|
jsTest.log.info("Skipping test Feature is not enabled");
|
|
quit();
|
|
}
|
|
|
|
configureFailPointForAllShardsAndMongos({
|
|
conn: db.getMongo(),
|
|
failPointName: "disablePipelineOptimization",
|
|
failPointMode: "off",
|
|
});
|
|
|
|
function explainPipeline(coll, pipeline) {
|
|
const explain = coll.explain().aggregate([{$_internalInhibitOptimization: {}}, ...pipeline]);
|
|
assert.eq(true, isAggregationPlan(explain), "Pipeline should not be optimized away");
|
|
return explain;
|
|
}
|
|
|
|
function isShardedHelper(coll, pipeline) {
|
|
const allStages = explainPipeline(coll, pipeline);
|
|
return FixtureHelpers.isSharded(coll) || "shards" in allStages;
|
|
}
|
|
|
|
const coll = db[jsTestName()];
|
|
|
|
function reInitializeCollScalarOnly(coll) {
|
|
coll.drop();
|
|
assert.commandWorked(coll.insert({_id: 0, test: 1}));
|
|
assert.commandWorked(coll.insert({_id: 1, test: 2}));
|
|
assert.commandWorked(coll.insert({_id: 2, test: 3}));
|
|
}
|
|
|
|
function addArraysToColl(coll) {
|
|
assert.commandWorked(coll.insert({_id: 3, test: [1, 2]}));
|
|
assert.commandWorked(coll.insert({_id: 4, test: [2, 3]}));
|
|
assert.commandWorked(coll.insert({_id: 5, test: [3, 4]}));
|
|
}
|
|
|
|
function runAndReturnStagesFromExplain(coll, query) {
|
|
const beforeAdditionalRule = explainPipeline(coll, query);
|
|
let allShardStages = [];
|
|
if (FixtureHelpers.isSharded(coll) || "shards" in beforeAdditionalRule) {
|
|
for (var shard in beforeAdditionalRule.shards) {
|
|
allShardStages.push(beforeAdditionalRule.shards[shard].stages);
|
|
}
|
|
allShardStages = allShardStages.flat();
|
|
} else {
|
|
if ("stages" in beforeAdditionalRule) {
|
|
allShardStages = beforeAdditionalRule.stages;
|
|
}
|
|
}
|
|
|
|
if (Array.isArray(allShardStages)) {
|
|
for (var i = 0; i < allShardStages.length; i++) {
|
|
var obj = allShardStages[i];
|
|
for (var key in obj) {
|
|
if (key == "$facet" && obj[key].hasOwnProperty("originalPipeline")) {
|
|
allShardStages = obj[key]["originalPipeline"];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return allShardStages;
|
|
}
|
|
|
|
// 1. Query only scalar with no indexes.
|
|
{
|
|
let query = [{$match: {test: 1}}];
|
|
|
|
reInitializeCollScalarOnly(coll);
|
|
|
|
if (!isShardedHelper(coll, query)) {
|
|
let allStagesBefore = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"test": {"$eq": 1}}},
|
|
allStagesBefore,
|
|
"The $match stage should contain only the original query",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", true);
|
|
|
|
let allStagesAfter = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"$and": [{"test": {"$type": [4]}}, {"test": {"$eq": 1}}]}},
|
|
allStagesAfter,
|
|
"The $match stage should be extended with the array type matching",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", false);
|
|
}
|
|
}
|
|
|
|
// 2. Query only scalar with indexes.
|
|
{
|
|
let query = [{$match: {test: 1}}];
|
|
|
|
reInitializeCollScalarOnly(coll);
|
|
assert.commandWorked(coll.createIndex({test: 1}));
|
|
|
|
if (!isShardedHelper(coll, query)) {
|
|
let allStagesBefore = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"test": {"$eq": 1}}},
|
|
allStagesBefore,
|
|
"The $match stage should contain only the original query",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", true);
|
|
|
|
let allStagesAfter = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"$and": [{"test": {"$not": {"$type": [4]}}}, {"test": {"$eq": 1}}]}},
|
|
allStagesAfter,
|
|
"The $match stage should be extended with the array type matching",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", false);
|
|
}
|
|
}
|
|
|
|
// 3. Query over both scalar and array value with indexes.
|
|
{
|
|
let query = [{$match: {test: 1}}];
|
|
|
|
reInitializeCollScalarOnly(coll);
|
|
addArraysToColl(coll);
|
|
assert.commandWorked(coll.createIndex({test: 1}));
|
|
|
|
if (!isShardedHelper(coll, query)) {
|
|
let allShardStagesBefore = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"test": {"$eq": 1}}},
|
|
allShardStagesBefore,
|
|
"The $match stage should contain only the original query",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", true);
|
|
|
|
let allShardStagesAfter = runAndReturnStagesFromExplain(coll, query);
|
|
assert.contains(
|
|
{"$match": {"$and": [{"test": {"$type": [4]}}, {"test": {"$eq": 1}}]}},
|
|
allShardStagesAfter,
|
|
"The $match stage should be extended with the array type matching",
|
|
);
|
|
|
|
setServerParameter("internalEnablePipelineOptimizationAdditionalTestingRules", false);
|
|
}
|
|
}
|