263 lines
10 KiB
JavaScript
263 lines
10 KiB
JavaScript
/**
|
|
* Utility for testing the parsing of densify-like commands. I.e. $_internalDensify and $densify.
|
|
*/
|
|
|
|
export 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) {
|
|
// 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'",
|
|
);
|
|
|
|
// 'partitionByFields' contains the field that is being desified.
|
|
assert.commandFailedWithCode(
|
|
run({
|
|
[stageName]: {field: "a", partitionByFields: ["a"], range: {step: 1.0, bounds: "full"}},
|
|
}),
|
|
8993000,
|
|
"BSON field '$densify.partitionByFields' contains the field that is being densified",
|
|
);
|
|
assert.commandFailedWithCode(
|
|
run({
|
|
[stageName]: {field: "a.b", partitionByFields: ["a"], range: {step: 1.0, bounds: "full"}},
|
|
}),
|
|
9554500,
|
|
"The field that is being densified contains the BSON field '$densify.partitionByFields'",
|
|
);
|
|
assert.commandFailedWithCode(
|
|
run({
|
|
[stageName]: {field: "a", partitionByFields: ["a.b"], range: {step: 1.0, bounds: "full"}},
|
|
}),
|
|
8993000,
|
|
"BSON field '$densify.partitionByFields' contains the field that is being densified",
|
|
);
|
|
|
|
assert.commandFailedWithCode(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
range: {
|
|
step: 1.0,
|
|
bounds: [new ISODate("2020-01-01"), new ISODate("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 ISODate("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 ISODate("2020-01-01"), new ISODate("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 ISODate("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 ISODate("2020-01-01"), 1], unit: "second"},
|
|
},
|
|
}),
|
|
5733402,
|
|
"a bounding array must be an ascending array of either two dates or two numbers",
|
|
);
|
|
// Non-whole number step with date bounds
|
|
assert.commandFailedWithCode(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
range: {
|
|
step: 1.1,
|
|
bounds: [new ISODate("2020-01-01"), new ISODate("2020-01-03")],
|
|
unit: "second",
|
|
},
|
|
},
|
|
}),
|
|
6586400,
|
|
"The step parameter in a range satement must be a whole number when densifying a date range",
|
|
);
|
|
|
|
// Positive test cases
|
|
assert.commandWorked(run({[stageName]: {field: "a", range: {step: 1.0, bounds: [1, 2]}}}));
|
|
assert.commandWorked(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
range: {
|
|
step: 1.0,
|
|
bounds: [new ISODate("2020-01-01"), new ISODate("2021-01-01")],
|
|
unit: "day",
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
partitionByFields: ["b", "c"],
|
|
range: {
|
|
step: 1.0,
|
|
bounds: [new ISODate("2020-01-01"), new ISODate("2021-01-01")],
|
|
unit: "week",
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
partitionByFields: ["b", "c"],
|
|
range: {step: 1.0, bounds: "partition", unit: "second"},
|
|
},
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
run({
|
|
[stageName]: {
|
|
field: "a",
|
|
partitionByFields: ["b", "c"],
|
|
range: {step: 1.0, bounds: "full", unit: "second"},
|
|
},
|
|
}),
|
|
);
|
|
assert.commandWorked(
|
|
run({
|
|
[stageName]: {field: "a", partitionByFields: ["b", "c"], range: {step: 1.0, bounds: "full"}},
|
|
}),
|
|
);
|
|
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);
|
|
};
|