303 lines
8.6 KiB
JavaScript
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));
|
|
}
|
|
} |