summaryrefslogtreecommitdiff
path: root/jstests/core/killop.js
blob: 7b44a8dacc4230e1f17081b32c294a51840c9114 (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
/**
 * Basic test of killop functionality.
 *
 * Theory of operation: Creates two operations that will take a long time, sends killop for those
 * operations, and then attempts to infer that the operations died because of killop, and not for
 * some other reason.
 *
 * NOTES:
 * The long operations are count({$where: function () { while (1) ; } }).  These operations do not
 * terminate until the server determines that they've spent too much time in JS execution, typically
 * after 30 seconds of wall clock time have passed.  For these operations to take a long time, the
 * counted collection must not be empty; hence an initial write to the collection is required.
 */
(function() {
    'use strict';

    var t = db.jstests_killop;
    t.save({x: 1});

    /**
     * This function filters for the operations that we're looking for, based on their state and
     * the contents of their query object.
     */
    function ops() {
        var p = db.currentOp().inprog;
        var ids = [];
        for (var i in p) {
            var o = p[i];
            // We *can't* check for ns, b/c it's not guaranteed to be there unless the query is
            // active, which it may not be in our polling cycle - particularly b/c we sleep every
            // second in both the query and the assert
            if ((o.active || o.waitingForLock) && o.query && o.query.query &&
                o.query.query.$where && o.query.count == "jstests_killop") {
                ids.push(o.opid);
            }
        }
        return ids;
    }

    jsTestLog("Starting long-running $where operation");
    var s1 = startParallelShell(
        "db.jstests_killop.count( { $where: function() { while( 1 ) { ; } } } )");
    var s2 = startParallelShell(
        "db.jstests_killop.count( { $where: function() { while( 1 ) { ; } } } )");

    jsTestLog("Finding ops in currentOp() output");
    var o = [];
    assert.soon(
        function() {
            o = ops();
            return o.length == 2;
        },
        {
          toString: function() {
              return tojson(db.currentOp().inprog);
          }
        },
        30000);

    var start = new Date();
    jsTestLog("Killing ops");
    db.killOp(o[0]);
    db.killOp(o[1]);

    jsTestLog("Waiting for ops to terminate");
    [s1, s2].forEach(function(awaitShell) {
        var exitCode = awaitShell({checkExitSuccess: false});
        assert.neq(
            0, exitCode, "expected shell to exit abnormally due to JS execution being terminated");
    });

    // don't want to pass if timeout killed the js function.
    var end = new Date();
    var diff = end - start;
    assert.lt(diff, 30000, "Start: " + start + "; end: " + end + "; diff: " + diff);
})();