diff options
Diffstat (limited to 'jstests/core/administrative/current_op/currentop_shell.js')
-rw-r--r-- | jstests/core/administrative/current_op/currentop_shell.js | 145 |
1 files changed, 145 insertions, 0 deletions
diff --git a/jstests/core/administrative/current_op/currentop_shell.js b/jstests/core/administrative/current_op/currentop_shell.js new file mode 100644 index 00000000000..9d52b4ca75c --- /dev/null +++ b/jstests/core/administrative/current_op/currentop_shell.js @@ -0,0 +1,145 @@ +/** + * Tests that the shell helper db.currentOpCursor isn't constrained by the legacy currentOp server + * command - ie. the result set isn't limited to 16MB and long operations aren't truncated. + * + * The test runs commands that are not allowed with security token: getLog. + * @tags: [ + * not_allowed_with_security_token, + * uses_parallel_shell, + * # This test uses currentOp to check whether an aggregate command is running. In replica set + * # environments, because currentOp is run against the admin database it is routed to the + * # primary, while the aggregate may be routed to a secondary. If currentOp is running on one + * # node and the expected command is run on another, the latter will not show up in the + * # currentOp results. + * assumes_read_preference_unchanged, + * no_selinux, + * # Uses $function operator. + * requires_scripting, + * ] + */ + +(function() { +"use strict"; + +load("jstests/libs/fixture_helpers.js"); // for FixtureHelpers + +const coll = db.currentOp_cursor; +coll.drop(); + +for (let i = 0; i < 3; i++) { + assert.commandWorked(coll.insert({val: 1})); +} + +// Test that db.currentOpCursor() returns an iterable cursor. +let res = db.currentOpCursor(); +assert(res.hasNext()); +assert(res.next()); + +// Test that db.currentOp() interface does not change. +res = db.currentOp(); +assert("inprog" in res, "Result contains 'inprog' field"); +assert("ok" in res, "Result contains 'ok' field"); + +// Attempting to access the fsyncLock field from the results throws with an error message. +let error = assert.throws(() => res.fsyncLock); +assert( + /fsyncLock is no longer included in the currentOp shell helper, run db\.runCommand\({currentOp: 1}\) instead/ + .test(error)); + +function shellOp() { + function createLargeDoc() { + let doc = {}; + for (let i = 0; i < 100; i++) { + doc[i] = "Testing testing 1 2 3..."; + } + return doc; + } + + assert.commandFailedWithCode(db.runCommand({ + aggregate: "currentOp_cursor", + pipeline: [{ + $addFields: { + newVal: {$function: {args: [], body: "sleep(1000000)", lang: "js"}}, + bigDoc: createLargeDoc() + } + }], + comment: TestData.comment, + cursor: {} + }), + ErrorCodes.Interrupted); +} + +function startShellWithOp(comment) { + TestData.comment = comment; + const awaitShell = startParallelShell(shellOp); + + // Confirm that the operation has started in the parallel shell. + assert.soon( + function() { + let aggRes = + db.getSiblingDB("admin") + .aggregate([ + {$currentOp: {}}, + {$match: {ns: "test.currentOp_cursor", "command.comment": TestData.comment}} + ]) + .toArray(); + return aggRes.length >= 1; + }, + function() { + return "Failed to find parallel shell operation in $currentOp output: " + + tojson(db.currentOp()); + }); + return awaitShell; +} + +// Test that the currentOp server command truncates long operations with a warning logged. +const serverCommandTest = startShellWithOp("currentOp_server"); +res = db.adminCommand({ + currentOp: true, + $and: [{"ns": "test.currentOp_cursor"}, {"command.comment": "currentOp_server"}] +}); + +if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) { + // Assert currentOp truncation behavior for each shard in the cluster. + assert(res.inprog.length >= 1, res); + res.inprog.forEach((result) => { + assert.eq(result.op, "getmore", result); + assert(result.cursor.originatingCommand.hasOwnProperty("$truncated"), result); + }); +} else { + // Assert currentOp truncation behavior for unsharded collections. + assert.eq(res.inprog.length, 1, res); + assert.eq(res.inprog[0].op, "command", res); + assert(res.inprog[0].command.hasOwnProperty("$truncated"), res); +} + +const log = FixtureHelpers.getPrimaryForNodeHostingDatabase(db).adminCommand({getLog: "global"}); +assert(/will be truncated/.test(log.log)); + +res.inprog.forEach((op) => { + assert.commandWorked(db.killOp(op.opid)); +}); + +serverCommandTest(); + +// Test that the db.currentOp() shell helper does not truncate ops. +const shellHelperTest = startShellWithOp("currentOp_shell"); +res = db.currentOp({"ns": "test.currentOp_cursor", "command.comment": "currentOp_shell"}); + +if (FixtureHelpers.isMongos(db) && FixtureHelpers.isSharded(coll)) { + assert(res.inprog.length >= 1, res); + res.inprog.forEach((result) => { + assert.eq(result.op, "getmore", result); + assert(!result.cursor.originatingCommand.hasOwnProperty("$truncated"), result); + }); +} else { + assert.eq(res.inprog.length, 1, res); + assert(!res.inprog[0].command.hasOwnProperty("$truncated"), res); +} + +res.inprog.forEach((op) => { + assert.commandWorked(db.killOp(op.opid)); +}); + +shellHelperTest(); +})(); |