149 lines
6.1 KiB
JavaScript
149 lines
6.1 KiB
JavaScript
/**
|
|
* Tests that invalid view definitions in system.views do not impact valid commands on existing
|
|
* collections.
|
|
*
|
|
* @tags: [
|
|
* # applyOps is not available on mongos.
|
|
* assumes_against_mongod_not_mongos,
|
|
* assumes_superuser_permissions,
|
|
* requires_non_retryable_commands,
|
|
* requires_non_retryable_writes,
|
|
* # applyOps uses the oplog that require replication support
|
|
* requires_replication,
|
|
* ]
|
|
*/
|
|
|
|
(function() {
|
|
"use strict";
|
|
const isMongos = db.runCommand({isdbgrid: 1}).isdbgrid;
|
|
const isStandalone = !isMongos && !db.runCommand({isMaster: 1}).hasOwnProperty("setName");
|
|
|
|
function runTest(badViewDefinition) {
|
|
let viewsDB = db.getSiblingDB("invalid_system_views");
|
|
assert.commandWorked(viewsDB.dropDatabase());
|
|
|
|
// Create a regular collection, then insert an invalid view into system.views.
|
|
assert.commandWorked(viewsDB.collection.insert({x: 1}));
|
|
assert.commandWorked(viewsDB.runCommand({create: "collection2"}));
|
|
assert.commandWorked(viewsDB.runCommand({create: "collection3"}));
|
|
assert.commandWorked(viewsDB.collection.createIndex({x: 1}));
|
|
assert.commandWorked(viewsDB.createCollection("system.views"));
|
|
assert.commandWorked(
|
|
viewsDB.adminCommand(
|
|
{applyOps: [{op: "i", ns: viewsDB.getName() + ".system.views", o: badViewDefinition}]}),
|
|
"failed to insert " + tojson(badViewDefinition));
|
|
|
|
// Test that a command involving views properly fails with a views-specific error code.
|
|
assert.commandFailedWithCode(
|
|
viewsDB.runCommand({listCollections: 1}),
|
|
ErrorCodes.InvalidViewDefinition,
|
|
"listCollections should have failed in the presence of an invalid view");
|
|
|
|
// Helper function to create a message to use if an assertion fails.
|
|
function makeErrorMessage(msg) {
|
|
return msg +
|
|
" should work on a valid, existing collection, despite the presence of bad views" +
|
|
" in system.views";
|
|
}
|
|
|
|
if (!isMongos) {
|
|
// Commands that run on existing regular collections should not be impacted by the
|
|
// presence of invalid views. However, applyOps doesn't work on mongos.
|
|
assert.commandWorked(
|
|
db.adminCommand( //
|
|
{applyOps: [{op: "c", ns: "invalid_system_views.$cmd", o: {drop: "collection3"}}]}),
|
|
makeErrorMessage("applyOps"));
|
|
}
|
|
|
|
assert.commandWorked(viewsDB.collection.insert({y: "baz"}), makeErrorMessage("insert"));
|
|
|
|
assert.commandWorked(viewsDB.collection.update({y: "baz"}, {$set: {y: "qux"}}),
|
|
makeErrorMessage("update"));
|
|
|
|
assert.commandWorked(viewsDB.collection.remove({y: "baz"}), makeErrorMessage("remove"));
|
|
|
|
assert.commandWorked(
|
|
viewsDB.runCommand({findAndModify: "collection", query: {x: 1}, update: {x: 2}}),
|
|
makeErrorMessage("findAndModify with update"));
|
|
|
|
assert.commandWorked(
|
|
viewsDB.runCommand({findAndModify: "collection", query: {x: 2}, remove: true}),
|
|
makeErrorMessage("findAndModify with remove"));
|
|
|
|
const lookup = {
|
|
$lookup: {from: "collection2", localField: "_id", foreignField: "_id", as: "match"}
|
|
};
|
|
assert.commandWorked(
|
|
viewsDB.runCommand({aggregate: "collection", pipeline: [lookup], cursor: {}}),
|
|
makeErrorMessage("aggregate with $lookup"));
|
|
|
|
const graphLookup = {
|
|
$graphLookup: {
|
|
from: "collection2",
|
|
startWith: "$_id",
|
|
connectFromField: "_id",
|
|
connectToField: "_id",
|
|
as: "match"
|
|
}
|
|
};
|
|
assert.commandWorked(
|
|
viewsDB.runCommand({aggregate: "collection", pipeline: [graphLookup], cursor: {}}),
|
|
makeErrorMessage("aggregate with $graphLookup"));
|
|
|
|
assert.commandWorked(viewsDB.runCommand({dropIndexes: "collection", index: "x_1"}),
|
|
makeErrorMessage("dropIndexes"));
|
|
|
|
assert.commandWorked(viewsDB.collection.createIndex({x: 1}), makeErrorMessage("createIndexes"));
|
|
|
|
// Only standalone mode supports the reIndex command.
|
|
if (isStandalone) {
|
|
assert.commandWorked(viewsDB.collection.reIndex(), makeErrorMessage("reIndex"));
|
|
}
|
|
|
|
const storageEngine = jsTest.options().storageEngine;
|
|
if (isMongos || storageEngine === "ephemeralForTest" || storageEngine === "inMemory" ||
|
|
storageEngine === "biggie") {
|
|
print("Not testing compact command on mongos or ephemeral storage engine");
|
|
} else {
|
|
assert.commandWorked(viewsDB.runCommand({compact: "collection", force: true}),
|
|
makeErrorMessage("compact"));
|
|
}
|
|
|
|
assert.commandWorked(
|
|
viewsDB.runCommand({collMod: "collection", validator: {x: {$type: "string"}}}),
|
|
makeErrorMessage("collMod"));
|
|
|
|
const renameCommand = {
|
|
renameCollection: "invalid_system_views.collection",
|
|
to: "invalid_system_views.collection2",
|
|
dropTarget: true
|
|
};
|
|
assert.commandWorked(viewsDB.adminCommand(renameCommand), makeErrorMessage("renameCollection"));
|
|
|
|
assert.commandWorked(viewsDB.runCommand({drop: "collection2"}), makeErrorMessage("drop"));
|
|
|
|
// Drop the offending view so that the validate hook succeeds.
|
|
assert.commandWorked(viewsDB.adminCommand(
|
|
{applyOps: [{op: "d", ns: viewsDB.getName() + ".system.views", o: badViewDefinition}]}));
|
|
}
|
|
|
|
runTest({_id: "invalid_system_views.badViewStringPipeline", viewOn: "collection", pipeline: "bad"});
|
|
runTest(
|
|
{_id: "invalid_system_views.badViewEmptyObjectPipeline", viewOn: "collection", pipeline: {}});
|
|
runTest({_id: "invalid_system_views.badViewNumericalPipeline", viewOn: "collection", pipeline: 7});
|
|
runTest({
|
|
_id: "invalid_system_views.badViewArrayWithIntegerPipeline",
|
|
viewOn: "collection",
|
|
pipeline: [1]
|
|
});
|
|
runTest({
|
|
_id: "invalid_system_views.badViewArrayWithEmptyArrayPipeline",
|
|
viewOn: "collection",
|
|
pipeline: [[]]
|
|
});
|
|
runTest({_id: 7, viewOn: "collection", pipeline: []});
|
|
runTest({_id: "invalid_system_views.embedded\0null", viewOn: "collection", pipeline: []});
|
|
runTest({_id: "invalidNotFullyQualifiedNs", viewOn: "collection", pipeline: []});
|
|
runTest({_id: "invalid_system_views.missingViewOnField", pipeline: []});
|
|
}());
|