Files
mongo/jstests/core/write/verify_update_mods.js
2023-08-06 20:48:04 +00:00

303 lines
8.6 KiB
JavaScript

/**
* Tests update and findAndModify command behavior with update modifiers.
*
* @tags: [
* # The test is designed to work with an unsharded collection.
* assumes_unsharded_collection,
* # Performs modifications that if repeated would fail the test.
* requires_non_retryable_writes,
* ]
*/
const testDB = db.getSiblingDB(jsTestName());
assert.commandWorked(testDB.dropDatabase());
const coll = testDB.update_modifiers;
// Executes a test case which inserts documents into the test collection, issues an update command,
// and verifies that the results are as expected.
function executeUpdateTestCase(testCase) {
jsTestLog(tojson(testCase));
// Remove all existing documents and then insert the new test case's documents.
assert.commandWorked(coll.remove({}));
assert.commandWorked(coll.insert(testCase.inputDocuments));
// Issue the update command specified in the test case.
const result = testCase.command(coll, testCase.query, testCase.update, testCase.arrayFilters);
if (testCase.expectedErrorCode == undefined) {
// Verify that the command succeeded and collection's contents match the expected results.
assert.commandWorked(result);
assert.docEq(testCase.expectedResults, coll.find({}).sort({_id: 1}).toArray());
} else {
assert.commandFailedWithCode(result, testCase.expectedErrorCode);
}
}
// Issues the update command and returns the response.
function updateCommand(coll, query, update, arrayFilters) {
const commandOptions = {upsert: true};
if (arrayFilters !== undefined) {
commandOptions.arrayFilters = arrayFilters;
}
return coll.update(query, update, commandOptions);
}
// Issues the findAndModify command and returns the response.
function findAndModifyCommand(coll, query, update, arrayFilters) {
const command = {query: query, update: update, upsert: true};
if (arrayFilters !== undefined) {
command.arrayFilters = arrayFilters;
}
return coll.runCommand("findAndModify", command);
}
// Tests all relevant update modifiers with set and empty update documents.
const testCases = [
{
query: {_id: 1},
update: {$set: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 2},
update: {$set: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}, {_id: 2}],
},
{
query: {_id: 1},
update: {$set: {a: 2}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 2}],
},
{
query: {_id: 1},
update: {$set: {}},
arrayFilters: [{"element": {$gt: 6}}],
inputDocuments: [{_id: 1, a: [1]}],
expectedErrorCode: ErrorCodes.FailedToParse,
},
{
query: {_id: 1},
update: {$unset: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$unset: {a: 1}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1}],
},
{
query: {_id: 1},
update: {$inc: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$inc: {a: 1}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 2}],
},
{
query: {_id: 1},
update: {$mul: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$mul: {a: 2}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 2}],
},
{
query: {_id: 1},
update: {$push: {}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1]}],
},
{
query: {_id: 1},
update: {$push: {a: 2}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1, 2]}],
},
{
query: {_id: 1},
update: {$addToSet: {}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1]}],
},
{
query: {_id: 1},
update: {$addToSet: {a: 2}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1, 2]}],
},
{
query: {_id: 1},
update: {$pull: {}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1]}],
},
{
query: {_id: 1},
update: {$pull: {a: 1}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: []}],
},
{
query: {_id: 1},
update: {$rename: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$rename: {a: "b"}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, b: 1}],
},
{
query: {_id: 1},
update: {$bit: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$bit: {a: {and: NumberLong(1)}}},
inputDocuments: [{_id: 1, a: NumberLong(2)}],
expectedResults: [{_id: 1, a: NumberLong(0)}],
},
{
query: {_id: 1},
update: {$bit: {a: {and: NumberLong(3)}}},
inputDocuments: [],
expectedResults: [{_id: 1, a: NumberLong(0)}],
},
{
query: {_id: 1},
update: {$bit: {b: {or: NumberLong(3)}}},
inputDocuments: [],
expectedResults: [{_id: 1, b: NumberLong(3)}],
},
{
query: {_id: 1},
update: {$bit: {"c.d": {or: NumberInt(3)}}},
inputDocuments: [],
expectedResults: [{_id: 1, c: {d: NumberInt(3)}}],
},
{
query: {_id: 1},
update: {$max: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$max: {a: 2}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 2}],
},
{
query: {_id: 1},
update: {$min: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$min: {a: 0}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 0}],
},
{
query: {_id: 1},
update: {$currentDate: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$setOnInsert: {}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 2},
update: {$setOnInsert: {a: 1}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}, {_id: 2, a: 1}],
},
{
query: {_id: 1},
update: {$setOnInsert: {a: 2}},
inputDocuments: [{_id: 1, a: 1}],
expectedResults: [{_id: 1, a: 1}],
},
{
query: {_id: 1},
update: {$pop: {}},
inputDocuments: [{_id: 1, a: [1]}],
expectedResults: [{_id: 1, a: [1]}],
},
{
query: {_id: 1},
update: {$pop: {a: true}},
inputDocuments: [{_id: 1, a: [1, 2]}],
expectedErrorCode: ErrorCodes.FailedToParse,
},
{
query: {_id: 1},
update: {$pop: {a: 1}},
inputDocuments: [{_id: 1, a: [1, 2]}],
expectedResults: [{_id: 1, a: [1]}],
},
{
query: {_id: 1},
update: {$pop: {a: -1}},
inputDocuments: [{_id: 1, a: [1, 2]}],
expectedResults: [{_id: 1, a: [2]}],
},
{
query: {_id: 1},
update: {$pop: {a: 1}},
inputDocuments: [{_id: 1, a: []}],
expectedResults: [{_id: 1, a: []}],
},
{
query: {_id: 1},
update: {$pop: {a: 1}},
inputDocuments: [],
expectedResults: [{_id: 1}],
},
{
query: {_id: 1},
update: {$currentDate: {}},
inputDocuments: [{_id: 1}],
expectedResults: [{_id: 1}],
},
{
query: {_id: 1},
update: {$pullAll: {}},
inputDocuments: [{_id: 1, a: [1, 2]}],
expectedResults: [{_id: 1, a: [1, 2]}],
},
{
query: {_id: 1},
update: {$pullAll: {a: [1]}},
inputDocuments: [{_id: 1, a: [1, 2, 1]}],
expectedResults: [{_id: 1, a: [2]}],
},
];
for (const command of [updateCommand, findAndModifyCommand]) {
for (const testCase of testCases) {
executeUpdateTestCase(Object.assign({command: command}, testCase));
}
}