345 lines
14 KiB
JavaScript
345 lines
14 KiB
JavaScript
/**
|
|
* Confirms inclusion of query, command object and planSummary in currentOp() for CRUD operations.
|
|
* This test should not be run in the parallel suite as it sets fail points.
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
/**
|
|
* @param {Object} params - Configuration options for the test.
|
|
* @param {string} params.readMode - The read mode to use for the parallel shell. This allows
|
|
* testing currentOp() output for both OP_QUERY and OP_GET_MORE queries, as well as "find" and
|
|
* "getMore" commands.
|
|
*/
|
|
function runTest(params) {
|
|
var conn = MongoRunner.runMongod({smallfiles: "", nojournal: ""});
|
|
assert.neq(null, conn, "mongod was unable to start up");
|
|
|
|
var testDB = conn.getDB("test");
|
|
assert.commandWorked(testDB.dropDatabase());
|
|
|
|
var coll = testDB.currentop_query;
|
|
|
|
// Force yield to occur on every PlanExecutor iteration.
|
|
assert.commandWorked(
|
|
testDB.adminCommand({setParameter: 1, internalQueryExecYieldIterations: 1}));
|
|
|
|
/**
|
|
* Captures currentOp() for a given test command/operation and confirms that namespace,
|
|
* operation type and planSummary are correct.
|
|
*
|
|
* @param {Object} testObj - Contains test arguments.
|
|
* @param {function} testObj.test - A function that runs the desired test op/cmd.
|
|
* @param {string} testObj.planSummary - A string containing the expected planSummary.
|
|
* @param {Object} testObj.currentOpFilter - A filter to be used to narrow currentOp()
|
|
* output to only the relevant operation or command.
|
|
* @param {string} [testObj.command] - The command to test against. Will look for this to
|
|
* be a key in the currentOp().query object.
|
|
* @param {string} [testObj.operation] - The operation to test against. Will look for this
|
|
* to be the value of the currentOp().op field.
|
|
*/
|
|
function confirmCurrentOpContents(testObj) {
|
|
// Force queries to hang on yield to allow for currentOp capture.
|
|
assert.commandWorked(testDB.adminCommand(
|
|
{configureFailPoint: "setYieldAllLocksHang", mode: "alwaysOn"}));
|
|
|
|
// Set shell read mode for the parallel shell test.
|
|
TestData.shellReadMode = params.readMode;
|
|
TestData.currentOpTest = testObj.test;
|
|
testObj.test = function() {
|
|
db.getMongo().forceReadMode(TestData.shellReadMode);
|
|
TestData.currentOpTest();
|
|
};
|
|
|
|
// Run query.
|
|
var awaitShell = startParallelShell(testObj.test, conn.port);
|
|
|
|
// Capture currentOp record for the query and confirm that the 'query' and 'planSummary'
|
|
// fields contain the content expected. We are indirectly testing the 'ns' field as well
|
|
// with the currentOp query argument.
|
|
assert.soon(
|
|
function() {
|
|
testObj.currentOpFilter.ns = coll.getFullName();
|
|
testObj.currentOpFilter.planSummary = testObj.planSummary;
|
|
if (testObj.hasOwnProperty("command")) {
|
|
testObj.currentOpFilter["query." + testObj.command] = {$exists: true};
|
|
} else if (testObj.hasOwnProperty("operation")) {
|
|
testObj.currentOpFilter.op = testObj.operation;
|
|
}
|
|
|
|
var result = testDB.currentOp(testObj.currentOpFilter);
|
|
assert.commandWorked(result);
|
|
|
|
if (result.inprog.length === 1) {
|
|
assert.eq(result.inprog[0].appName, "MongoDB Shell", tojson(result));
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
},
|
|
function() {
|
|
return "Failed to find operation from " + tojson(testObj) +
|
|
" in currentOp() output: " + tojson(testDB.currentOp());
|
|
});
|
|
|
|
// Allow the query to complete.
|
|
assert.commandWorked(
|
|
testDB.adminCommand({configureFailPoint: "setYieldAllLocksHang", mode: "off"}));
|
|
|
|
awaitShell();
|
|
delete TestData.currentOpTest;
|
|
delete TestData.shellReadMode;
|
|
}
|
|
|
|
//
|
|
// Confirm currentOp content for commands defined in 'testList'.
|
|
//
|
|
var testList = [
|
|
{
|
|
test: function() {
|
|
assert.eq(db.currentop_query
|
|
.aggregate([{$match: {a: 1, $comment: "currentop_query"}}],
|
|
{collation: {locale: "fr"}})
|
|
.itcount(),
|
|
1);
|
|
},
|
|
command: "aggregate",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {
|
|
"query.pipeline.0.$match.$comment": "currentop_query",
|
|
"query.collation": {locale: "fr"}
|
|
}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.eq(db.currentop_query.find({a: 1, $comment: "currentop_query"})
|
|
.collation({locale: "fr"})
|
|
.count(),
|
|
1);
|
|
},
|
|
command: "count",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter:
|
|
{"query.query.$comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.eq(
|
|
db.currentop_query.distinct(
|
|
"a", {a: 1, $comment: "currentop_query"}, {collation: {locale: "fr"}}),
|
|
[1]);
|
|
},
|
|
command: "distinct",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter:
|
|
{"query.query.$comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.eq(db.currentop_query.find({a: 1}).comment("currentop_query").itcount(),
|
|
1);
|
|
},
|
|
command: "find",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {"query.comment": "currentop_query"}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.eq(db.currentop_query.findAndModify({
|
|
query: {a: 1, $comment: "currentop_query"},
|
|
update: {$inc: {b: 1}},
|
|
collation: {locale: "fr"}
|
|
}),
|
|
{"_id": 1, "a": 1});
|
|
},
|
|
command: "findandmodify",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter:
|
|
{"query.query.$comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.eq(db.currentop_query.group({
|
|
key: {a: 1},
|
|
cond: {a: 1, $comment: "currentop_query"},
|
|
reduce: function() {},
|
|
initial: {},
|
|
collation: {locale: "fr"}
|
|
}),
|
|
[{"a": 1}]);
|
|
},
|
|
command: "group",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {
|
|
"query.group.cond.$comment": "currentop_query",
|
|
"query.group.collation": {locale: "fr"}
|
|
}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.commandWorked(db.currentop_query.mapReduce(
|
|
function() {
|
|
emit(this.a, this.b);
|
|
},
|
|
function(a, b) {
|
|
return Array.sum(b);
|
|
},
|
|
{
|
|
query: {a: 1, $comment: "currentop_query"},
|
|
out: {inline: 1},
|
|
collation: {locale: "fr"}
|
|
}));
|
|
},
|
|
command: "mapreduce",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter:
|
|
{"query.query.$comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.writeOK(db.currentop_query.remove({a: 2, $comment: "currentop_query"},
|
|
{collation: {locale: "fr"}}));
|
|
},
|
|
operation: "remove",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {"query.$comment": "currentop_query", "collation": {locale: "fr"}}
|
|
},
|
|
{
|
|
test: function() {
|
|
assert.writeOK(db.currentop_query.update({a: 1, $comment: "currentop_query"},
|
|
{$inc: {b: 1}},
|
|
{collation: {locale: "fr"}}));
|
|
},
|
|
operation: "update",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {"query.$comment": "currentop_query", "collation": {locale: "fr"}}
|
|
}
|
|
];
|
|
|
|
coll.drop();
|
|
var i;
|
|
for (i = 0; i < 5; ++i) {
|
|
assert.writeOK(coll.insert({_id: i, a: i}));
|
|
}
|
|
|
|
testList.forEach(confirmCurrentOpContents);
|
|
|
|
//
|
|
// Confirm currentOp contains collation for find command.
|
|
//
|
|
if (params.readMode === "commands") {
|
|
confirmCurrentOpContents({
|
|
test: function() {
|
|
assert.eq(db.currentop_query.find({a: 1})
|
|
.comment("currentop_query")
|
|
.collation({locale: "fr"})
|
|
.itcount(),
|
|
1);
|
|
},
|
|
command: "find",
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter:
|
|
{"query.comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
});
|
|
}
|
|
|
|
//
|
|
// Confirm currentOp content for geoNear.
|
|
//
|
|
coll.drop();
|
|
for (i = 0; i < 10; ++i) {
|
|
assert.writeOK(coll.insert({a: i, loc: {type: "Point", coordinates: [i, i]}}));
|
|
}
|
|
assert.commandWorked(coll.createIndex({loc: "2dsphere"}));
|
|
|
|
confirmCurrentOpContents({
|
|
test: function() {
|
|
assert.commandWorked(db.runCommand({
|
|
geoNear: "currentop_query",
|
|
near: {type: "Point", coordinates: [1, 1]},
|
|
spherical: true,
|
|
query: {$comment: "currentop_query"},
|
|
collation: {locale: "fr"}
|
|
}));
|
|
},
|
|
command: "geoNear",
|
|
planSummary: "GEO_NEAR_2DSPHERE { loc: \"2dsphere\" }",
|
|
currentOpFilter:
|
|
{"query.query.$comment": "currentop_query", "query.collation": {locale: "fr"}}
|
|
});
|
|
|
|
//
|
|
// Confirm currentOp content for getMore.
|
|
//
|
|
coll.drop();
|
|
for (i = 0; i < 10; ++i) {
|
|
assert.writeOK(coll.insert({a: i}));
|
|
}
|
|
|
|
var cmdRes = testDB.runCommand(
|
|
{find: "currentop_query", filter: {$comment: "currentop_query"}, batchSize: 0});
|
|
assert.commandWorked(cmdRes);
|
|
|
|
TestData.commandResult = cmdRes;
|
|
|
|
var filter;
|
|
if (params.readMode === "legacy") {
|
|
filter = {"op": "getmore", "query.filter.$comment": "currentop_query"};
|
|
} else {
|
|
filter = {
|
|
"query.getMore": TestData.commandResult.cursor.id,
|
|
"originatingCommand.filter.$comment": "currentop_query"
|
|
};
|
|
}
|
|
|
|
confirmCurrentOpContents({
|
|
test: function() {
|
|
var cursor = new DBCommandCursor(db.getMongo(), TestData.commandResult, 5);
|
|
assert.eq(cursor.itcount(), 10);
|
|
},
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: filter
|
|
});
|
|
|
|
delete TestData.commandResult;
|
|
|
|
//
|
|
// Confirm 512 byte size limit for currentOp query field.
|
|
//
|
|
coll.drop();
|
|
assert.writeOK(coll.insert({a: 1}));
|
|
|
|
// When the currentOp command serializes the query object as a string, individual string
|
|
// values inside it are truncated at 150 characters. To test "total length" truncation we
|
|
// need to pass multiple values, each smaller than 150 bytes.
|
|
TestData.queryFilter = {
|
|
"1": "1".repeat(100),
|
|
"2": "2".repeat(100),
|
|
"3": "3".repeat(100),
|
|
"4": "4".repeat(100),
|
|
"5": "5".repeat(100),
|
|
"6": "6".repeat(100),
|
|
};
|
|
var truncatedQueryString = "{ find: \"currentop_query\", filter: { " +
|
|
"1: \"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\", " +
|
|
"2: \"2222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222\", " +
|
|
"3: \"3333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333\", " +
|
|
"4: \"4444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444444\", " +
|
|
"5: \"5555555555555555555555555555555555555555...";
|
|
|
|
confirmCurrentOpContents({
|
|
test: function() {
|
|
assert.eq(db.currentop_query.find(TestData.queryFilter).itcount(), 0);
|
|
},
|
|
planSummary: "COLLSCAN",
|
|
currentOpFilter: {"query": truncatedQueryString}
|
|
});
|
|
|
|
delete TestData.queryFilter;
|
|
}
|
|
|
|
runTest({readMode: "commands"});
|
|
runTest({readMode: "legacy"});
|
|
})();
|