diff options
Diffstat (limited to 'jstests/aggregation/sources/densify/libs/parse_util.js')
-rw-r--r-- | jstests/aggregation/sources/densify/libs/parse_util.js | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/jstests/aggregation/sources/densify/libs/parse_util.js b/jstests/aggregation/sources/densify/libs/parse_util.js new file mode 100644 index 00000000000..9e51df53445 --- /dev/null +++ b/jstests/aggregation/sources/densify/libs/parse_util.js @@ -0,0 +1,210 @@ +/** + * Utility for testing the parsing of densify-like commands. I.e. $_internalDensify and $densify. + */ + +let parseUtil = (function(db, coll, stageName, options = {}) { + function run(stage, extraCommandArgs = options) { + return coll.runCommand(Object.merge( + {aggregate: coll.getName(), pipeline: [stage], cursor: {}}, extraCommandArgs)); + } + + function runTest(stageName) { + const featureEnabled = + assert.commandWorked(db.adminCommand({getParameter: 1, featureFlagDensify: 1})) + .featureFlagDensify.value; + if (!featureEnabled) { + jsTestLog("Skipping test because the densify feature flag is disabled"); + return; + } + + // Required fields. + const kIDLRequiredFieldErrorCode = 40414; + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: 1.0}}}), + kIDLRequiredFieldErrorCode, + "BSON field '$densify.range.bounds' is missing but a required field"); + assert.commandFailedWithCode(run({[stageName]: {range: {step: 1.0, bounds: "full"}}}), + kIDLRequiredFieldErrorCode, + "BSON field '$densify.field' is missing but a required field"); + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {bounds: "full"}}}), + kIDLRequiredFieldErrorCode, + "BSON field '$densify.range.step' is missing but a required field"); + + // Wrong types + assert.commandFailedWithCode( + run({[stageName]: {field: 1.0, range: {step: 1.0, bounds: "full"}}}), + ErrorCodes.TypeMismatch, + "BSON field '$densify.field' is the wrong type 'double', expected type 'string'"); + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: "invalid", bounds: "full"}}}), + ErrorCodes.TypeMismatch, + "BSON field '$densify.range.step' is the wrong type 'string', expected types '[int, decimal, double, long']"); + assert.commandFailedWithCode( + run({ + [stageName]: + {field: "a", partitionByFields: "incorrect", range: {step: 1.0, bounds: "full"}} + }), + ErrorCodes.TypeMismatch, + "BSON field '$densify.partitionByFields' is the wrong type 'string', expected type 'array'"); + assert.commandFailedWithCode( + run({ + [stageName]: { + field: "a", + range: { + step: 1.0, + bounds: [new Date("2020-01-01"), new Date("2020-01-02")], + unit: 1000 + } + } + }), + ErrorCodes.TypeMismatch, + "BSON field '$densify.range.unit' is the wrong type 'double', expected type 'string'"); + + // Logical errors + // Too few bounds + assert.commandFailedWithCode( + run({ + [stageName]: { + field: "a", + range: {step: 1.0, bounds: [new Date("2020-01-01")], unit: "second"} + } + }), + 5733403, + "a bounding array in a range statement must have exactly two elements"); + // Too many elements + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: 1.0, bounds: [0, 1, 2]}}}), + 5733403, + "a bounding array in a range statement must have exactly two elements"); + // Negative step + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: -1.0, bounds: [0, 1]}}}), + 5733401, + "the step parameter in a range statement must be a strictly positive numeric value"); + // Field path expression instead of field path + assert.commandFailedWithCode( + run({[stageName]: {field: "$a", range: {step: 1.0, bounds: [0, 1]}}}), + 16410, + "FieldPath field names may not start with '$'. Consider using $getField or $setField."); + // Field path expression instead of field path + assert.commandFailedWithCode( + run({ + [stageName]: + {field: "a", partitionByFields: ["$b"], range: {step: 1.0, bounds: [0, 1]}} + }), + 16410, + "FieldPath field names may not start with '$'. Consider using $getField or $setField."); + // Partition bounds but not partitionByFields + assert.commandFailedWithCode( + run({ + [stageName]: + {field: "a", partitionByFields: [], range: {step: 1.0, bounds: "partition"}} + }), + 5733408, + "one may not specify the bounds as 'partition' without specifying a non-empty array of partitionByFields. You may have meant to specify 'full' bounds."); + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: 1.0, bounds: "partition"}}}), + 5733408, + "one may not specify the bounds as 'partition' without specifying a non-empty array of partitionByFields. You may have meant to specify 'full' bounds."); + // Left bound greater than right bound + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: 1.0, bounds: [2, 1]}}}), + 5733402, + "the bounds in a range statement must be the string 'full', 'partition', or an ascending array of two numbers or two dates"); + assert.commandFailedWithCode( + run({ + [stageName]: { + field: "a", + range: { + step: 1.0, + bounds: [new Date("2020-01-01"), new Date("2019-01-01")], + unit: "second" + } + } + }), + 5733402, + "the bounds in a range statement must be the string 'full', 'partition', or an ascending array of two numbers or two dates"); + // Unit with numeric bounds + assert.commandFailedWithCode( + run({[stageName]: {field: "a", range: {step: 1.0, bounds: [1, 2], unit: "second"}}}), + 5733409, + "numeric bounds may not have unit parameter"); + // Mixed numeric and date bounds + assert.commandFailedWithCode( + run({ + [stageName]: {field: "a", range: {step: 1.0, bounds: [1, new Date("2020-01-01")]}} + }), + 5733406, + "a bounding array must contain either both dates or both numeric types"); + assert.commandFailedWithCode( + run({ + [stageName]: { + field: "a", + range: {step: 1.0, bounds: [new Date("2020-01-01"), 1], unit: "second"} + } + }), + 5733402, + "a bounding array must be an ascending array of either two dates or two numbers"); + + // Positive test cases + assert.commandWorked(run({[stageName]: {field: "a", range: {step: 1.0, bounds: [1, 2]}}})); + // TODO SERVER-57337: Enable this parsing test. + /* assert.commandWorked(run({ + * [stageName]: { + * field: "a", + * range: { + * step: 1.0, + * bounds: [new Date("2020-01-01"), new Date("2021-01-01")], + * unit: "second" + * } + * } + * })); */ + // TODO SERVER-57337 SERVER-57344: Enable this parsing test. + /* assert.commandWorked(run({ + * [stageName]: { + * field: "a", + * partitionByFields: ["b", "c"], + * range: { + * step: 1.0, + * bounds: [new Date("2020-01-01"), new Date("2021-01-01")], + * unit: "second" + * } + * } + * })); */ + // TODO SERVER-57337 SERVER-57344: Enable this parsing test. + /* assert.commandWorked(run({ + * [stageName]: { + * field: "a", + * partitionByFields: ["b", "c"], + * range: {step: 1.0, bounds: "partition", unit: "second"} + * } + * })); */ + // TODO SERVER-57337 SERVER-57344: Enable this parsing test. + /* assert.commandWorked(run({ + * [stageName]: { + * field: "a", + * partitionByFields: ["b", "c"], + * range: {step: 1.0, bounds: "full", unit: "second"} + * } + * })); */ + // TODO SERVER-57344: Enable this parsing test. + /* assert.commandWorked(run({ + * [stageName]: + * {field: "a", partitionByFields: ["b", "c"], range: {step: 1.0, bounds: "full"}} + * })); */ + // TODO SERVER-57344: Enable this parsing test. + /* assert.commandWorked(run({ + [stageName]: { + field: "a", + partitionByFields: [ + "b", + ], + range: { step: 1.0, bounds: "partition" } + } + })); */ + assert.commandWorked(run({[stageName]: {field: "a", range: {step: 1.0, bounds: "full"}}})); + } + + runTest(stageName); +}); |