summaryrefslogtreecommitdiff
path: root/jstests/core/mr_fail_invalid_js.js
blob: 01b422c1fe3c9b23a5b00e8969223ccfe9153710 (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
// Tests that mapReduce fails gracefully when given a map or reduce function which fails in some
// way.
// @tags: [
//   # mapReduce does not support afterClusterTime.
//   does_not_support_causal_consistency,
//   does_not_support_stepdowns,
//   uses_map_reduce_with_temp_collections,
// ]
(function() {
"use strict";

const coll = db.mr_fail_invalid_js;
const outputColl = db.mr_fail_invalid_js_out;

// Test that a map or reduce function which references a path which doesn't exist fails gracefully.
(function testReferencingInvalidPaths() {
    coll.drop();
    outputColl.drop();

    assert.commandWorked(coll.insert([
        {x: 1, tags: ["a", "b"]},
        {x: 2, tags: ["b", "c"]},
        {x: 3, tags: ["c", "a"]},
        {x: 4, tags: ["b", "c"]}
    ]));

    let reduceFn = function(key, values) {
        return Array.sum(values);
    };

    const goodMapFn = function() {
        for (let tag of this.tags) {
            emit(tag, 1);
        }
    };
    assert.commandWorked(coll.mapReduce(goodMapFn, reduceFn, {out: {merge: outputColl.getName()}}));
    outputColl.drop();

    // mapReduce fails when attempting to merge a missing key.
    const singleInvalidPathMapFn = function() {
        emit(this.missing_field, this.x);
    };

    assert.throws(() => coll.mapReduce(
                      singleInvalidPathMapFn, reduceFn, {out: {merge: outputColl.getName()}}),
                  []);

    // Now test that a traversal through a missing path will cause an error.
    const badMapFn = function() {
        emit(this._id, this.missing_field.nested_missing);
    };

    assert.throws(
        () => coll.mapReduce(newMapFn, reduceFn, {out: {merge: outputColl.getName()}}),
        [],
        "expected mapReduce to throw because map function references path that does not exist");

    // Test the same thing but in the reduce function.
    reduceFn = function(k, v) {
        return v.missing_field.increasingly_missing.all_hope_is_lost;
    };
    assert.throws(
        () => coll.mapReduce(goodMapFn, reduceFn, outputColl.getName()),
        [],
        "expected mapReduce to throw because reduce function references path that does not exist");
}());

// Test that a map function which supplies the wrong number of arguments to 'emit' will fail
// gracefully.
(function testBadCallToEmit() {
    coll.drop();
    outputColl.drop();
    assert.commandWorked(coll.insert([{a: [1, 2, 3]}, {a: [2, 3, 4]}]));
    const goodMapFn = function() {
        for (let i = 0; i < this.a.length; i++) {
            emit(this.a[i], 1);
        }
    };

    const goodReduceFn = function(k, v) {
        let total = 0;
        for (let i = 0; i < v.length; i++)
            total += v[i];
        return total;
    };

    // First test that a valid command succeeds.
    let res = coll.mapReduce(goodMapFn, goodReduceFn, {out: {merge: outputColl.getName()}});

    assert.eq([{_id: 1, value: 1}, {_id: 2, value: 2}, {_id: 3, value: 2}, {_id: 4, value: 1}],
              outputColl.find().sort({_id: 1}).toArray());
    assert(outputColl.drop());

    const badMapFn = function() {
        for (let i = 0; i < this.a.length; i++) {
            emit(this.a[i]);
        }
    };

    const error = assert.commandFailed(db.runCommand({
        mapReduce: coll.getName(),
        map: badMapFn,
        reduce: goodReduceFn,
        out: outputColl.getName()
    }));
    assert(error.errmsg.indexOf("emit") >= 0, () => tojson(error));

    // Test that things are still in an ok state and the next mapReduce can succeed.
    outputColl.drop();
    assert.commandWorked(
        coll.mapReduce(goodMapFn, goodReduceFn, {out: {merge: outputColl.getName()}}));
    assert.eq([{_id: 1, value: 1}, {_id: 2, value: 2}, {_id: 3, value: 2}, {_id: 4, value: 1}],
              outputColl.find().sort({_id: 1}).toArray());
    assert(outputColl.drop());
}());
}());