mongo/jstests/aggregation/expressions/expression_set_field_null_c...

121 lines
4.6 KiB
JavaScript

/**
* Tests that $setField handles null chars in the 'field' argument correctly.
*
* @tags: [
* # The test runs commands that are not allowed with security token: bulkWrite.
* not_allowed_with_signed_security_token,
* # TODO SERVER-96515 Remove this tag.
* # The config fuzzer also manipulates query stats knobs.
* does_not_support_config_fuzzer,
* ]
*/
const coll = db[jsTestName()];
coll.drop();
assert.commandWorked(coll.insert({_id: 1, foo: "bar"}));
// Asserts $setField and $unsetField with the given 'field' argument fail with one of the given
// 'codes' when used in various commands.
function assertSetFieldFailsWithCode({field, codes}) {
const setFieldExpressions = [{$setField: {field, input: {}, value: true}}, {$unsetField: {field, input: {}}}];
for (const setFieldExpression of setFieldExpressions) {
const errorMsg = tojson(setFieldExpression);
assert.commandFailedWithCode(
db.runCommand({find: coll.getName(), projection: {field: setFieldExpression}}),
codes,
errorMsg,
);
assert.commandFailedWithCode(
db.runCommand({
aggregate: coll.getName(),
pipeline: [{$project: {field: setFieldExpression}}, {$out: coll.getName() + "-2"}],
cursor: {},
}),
codes,
errorMsg,
);
assert.commandFailedWithCode(
db.runCommand({
aggregate: coll.getName(),
pipeline: [
{
$merge: {
into: coll.getName(),
whenMatched: [{$replaceWith: setFieldExpression}],
whenNotMatched: "discard",
},
},
],
cursor: {},
}),
codes,
errorMsg,
);
assert.commandFailedWithCode(
db.runCommand({
update: coll.getName(),
updates: [{q: {_id: 1}, u: [{$replaceWith: setFieldExpression}], multi: false}],
}),
codes,
errorMsg,
);
assert.commandFailedWithCode(
db.runCommand({
findAndModify: coll.getName(),
query: {_id: 1},
update: [{$replaceWith: setFieldExpression}],
}),
codes,
errorMsg,
);
// Only the nested update command fails here. The shell helper 'coll.bulkWrite()' would
// throw in that case, but 'assert.throwsWithCode()' can't pull the error code from
// 'BulkWriteError'.
const bulkWriteRes = assert.commandWorked(
db.adminCommand({
bulkWrite: 1,
ops: [{update: 0, filter: {_id: 1}, updateMods: [{$replaceWith: setFieldExpression}]}],
nsInfo: [{ns: `${db.getName()}.${coll.getName()}`}],
}),
);
assert(codes.some((code) => code == bulkWriteRes.cursor.firstBatch[0].code));
}
}
const invalidFieldNames = [
// Starts with null chars.
"\x00a",
// Ends with null chars.
"a\x00",
// All null chars.
"\x00",
"\x00\x00\x00",
// Null chars somewhere in the middle.
"a\x00\x01\x08a",
"a\x00\x02\x08b",
"a\x00\x01\x18b",
"a\x00\x01\x28c",
"a\x00\x01\x03d\x00\xff\xff\xff\xff\x00\x08b",
];
// Test each field name directly, as part of a field reference, wrapped in $const/$literal,
// wrapped in a const-foldable expression as well as some combinations of these.
for (const field of invalidFieldNames) {
assertSetFieldFailsWithCode({field, codes: [9534700, 9423101]});
assertSetFieldFailsWithCode({field: {$const: field}, codes: [9534700, 9423101]});
assertSetFieldFailsWithCode({field: {$literal: field}, codes: [9534700, 9423101]});
assertSetFieldFailsWithCode({field: "$" + field, codes: [16411, 9423101]});
assertSetFieldFailsWithCode({field: "$foo." + field, codes: [16411, 9423101]});
assertSetFieldFailsWithCode({field: "foo." + field, codes: [9534700, 9423101]});
assertSetFieldFailsWithCode({field: {$const: "$" + field}, codes: [9534700, 9423101]});
assertSetFieldFailsWithCode({field: {$const: "$foo." + field}, codes: [9534700, 9423101]});
// Sanity check: non-literal expressions are not allowed even when they could be const
// folded.
assertSetFieldFailsWithCode({field: {$concat: [field]}, codes: [4161106, 9423101]});
assertSetFieldFailsWithCode({field: {$toUpper: field}, codes: [4161106, 9423101]});
assertSetFieldFailsWithCode({field: {$toLower: field}, codes: [4161106, 9423101]});
}