summaryrefslogtreecommitdiff
path: root/jstests/core/comment_field.js
blob: b7c226090e497603f9a2815acd4dd3320b974b19 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
 * Test to verify that the 'comment' field set while running a command gets populated in $currentOp
 * and profiler.
 * @tags: [
 *   assumes_against_mongod_not_mongos,
 *   assumes_read_concern_unchanged,
 *   assumes_unsharded_collection,
 *   assumes_write_concern_unchanged,
 *   does_not_support_stepdowns,
 *   requires_profiling,
 *   uses_parallel_shell,
 *   no_selinux,
 *   # This test uses legacy read mode which does not use runCommand (required by the
 *   # inject_tenant_prefix.js override).
 *   tenant_migration_incompatible,
 * ]
 */

(function() {
"use strict";

load("jstests/libs/profiler.js");  // For profilerHas*OrThrow helper functions.

// This test runs manual getMores using different connections, which will not inherit the
// implicit session of the cursor establishing command.
TestData.disableImplicitSessions = true;

const testDB = db.getSiblingDB(jsTestName());
const adminDB = db.getSiblingDB("admin");

const coll = testDB.coll;
coll.drop();

assert.commandWorked(coll.insert({x: 1, _id: 1}));
assert.commandWorked(coll.insert({x: 1, _id: 2}));

function setPostCommandFailpoint({mode, options}) {
    assert.commandWorked(db.adminCommand(
        {configureFailPoint: "waitAfterCommandFinishesExecution", mode: mode, data: options}));
}

function restartProfiler() {
    // Restart profiler.
    testDB.setProfilingLevel(0);
    testDB.system.profile.drop();
    testDB.setProfilingLevel(2);
}

function runCommentParamTest({coll, command, commentObj}) {
    const cmdName = Object.keys(command)[0];
    if (!commentObj) {
        commentObj = {testName: jsTestName(), commentField: "comment_" + cmdName};
        command["comment"] = commentObj;
    }
    restartProfiler();

    let parallelShell;
    try {
        setPostCommandFailpoint(
            {mode: "alwaysOn", options: {ns: coll.getFullName(), commands: [cmdName]}});

        const parallelFn = `
            const sourceDB = db.getSiblingDB(jsTestName());
            let cmdRes = sourceDB.runCommand(${tojson(command)});
            assert.commandWorked(cmdRes); `;

        // Run the 'command' in a parallel shell.
        parallelShell = startParallelShell(parallelFn);

        // Wait for the parallel shell to hit the failpoint and verify that the 'comment' field is
        // present in $currentOp.
        const filter = {[`command.${cmdName}`]: {$exists: true}, "command.comment": commentObj};

        assert.soon(
            () => adminDB.aggregate([{$currentOp: {}}, {$match: filter}]).toArray().length == 1,
            () => tojson(adminDB.aggregate([{$currentOp: {}}]).toArray()));

    } finally {
        // Ensure that we unset the failpoint, regardless of the outcome of the test.
        setPostCommandFailpoint({mode: "off", options: {}});
    }
    // Wait for the parallel shell to complete.
    parallelShell();

    // Verify that profile entry has 'comment' field.
    profilerHasSingleMatchingEntryOrThrow(
        {profileDB: testDB, filter: {"command.comment": commentObj}});
}

// Verify that the comment attached to a find command appears in both currentOp and the profiler.
runCommentParamTest({coll: coll, command: {find: coll.getName(), filter: {}}});

// Verify that the comment attached to an insert command appears in both currentOp and the profiler.
runCommentParamTest({
    coll: coll,
    command: {insert: coll.getName(), documents: [{x: 0.5}, {x: -0.5}], ordered: false}
});

// Verify that the comment attached to an aggregate command appears in both currentOp and the
// profiler.
runCommentParamTest({
    coll: coll,
    command: {aggregate: coll.getName(), pipeline: [], cursor: {batchSize: 1}},
});

// Verify the 'comment' field on the aggreage command is propagated to the subsequent getMore
// command.
const comment = [{name: "agg_comment"}];
const res = testDB.runCommand(
    {aggregate: coll.getName(), pipeline: [], comment: comment, cursor: {batchSize: 1}});
runCommentParamTest({
    coll: coll,
    command: {getMore: res.cursor.id, collection: coll.getName(), batchSize: 1},
    commentObj: comment
});

// Verify the 'comment' field on the getMore command takes precedence over the 'comment' field on
// the originating command.
runCommentParamTest(
    {coll: coll, command: {getMore: res.cursor.id, collection: coll.getName(), batchSize: 1}});

// Verify that comment field gets populated on the profiler for aggregate with explain:true.
runCommentParamTest({
    coll: coll,
    command: {aggregate: coll.getName(), pipeline: [], explain: true},
});

const innerComment = {
    name: "innerComment_aggregation"
};

// Verify that a comment field attached to the inner command of an explain command gets populated in
// profiler as top level 'comment'.
runCommentParamTest({
    coll: coll,
    command:
        {explain: {aggregate: coll.getName(), pipeline: [], cursor: {}, comment: innerComment}},
    commentObj: innerComment
});

// Verify that when a comment field is attached to the inner command of an explain command and there
// is another 'comment' field at the top level, top level comment takes precedence.
runCommentParamTest({
    coll: coll,
    command: {explain: {aggregate: coll.getName(), pipeline: [], cursor: {}, comment: innerComment}}
});
})();