summaryrefslogtreecommitdiff
path: root/jstests/replsets/agg_write_concern_zero_batch_size.js
blob: 2532a5da68f4c3824743605eebe3c06eba438fa8 (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
// Tests that an aggregate sent with batchSize: 0 will still obey the write concern sent on the
// original request, even though the writes happen in the getMore.
(function() {
"use strict";

load("jstests/aggregation/extras/merge_helpers.js");  // For withEachKindOfWriteStage.
load("jstests/libs/write_concern_util.js");           // For [stop|restart]ServerReplication.

// When calling replTest.getPrimary(), the slaveOk bit will be set to true, which will result in
// running all commands with a readPreference of 'secondaryPreferred'. This is problematic in a
// mixed 4.2/4.4 Replica Set cluster as running $out/$merge  with non-primary read preference
// against a cluster in FCV 4.2 is not allowed. As such, setting this test option provides a
// means to ensure that the commands in this test file run with readPreference 'primary'.
TestData.shouldSkipSettingSlaveOk = true;

// Start a replica set with two nodes: one with the default configuration and one with priority
// zero to ensure we don't have any elections.
const rst = new ReplSetTest({nodes: [{}, {rsConfig: {priority: 0}}]});
rst.startSet();
rst.initiate();

const testDB = rst.getPrimary().getDB("test");
const source = testDB.agg_write_concern_zero_batch_size;
const target = testDB.agg_write_concern_zero_batch_size_target;
assert.commandWorked(source.insert([{_id: 0}, {_id: 1}, {_id: 2}]));

withEachKindOfWriteStage(target, (stageSpec) => {
    assert.commandWorked(target.remove({}));

    // Start an aggregate cursor with a writing stage, but use batchSize: 0 to prevent any
    // writes from happening in this command.
    const response = assert.commandWorked(testDB.runCommand({
        aggregate: source.getName(),
        pipeline: [stageSpec],
        writeConcern: {w: 2, wtimeout: 100},
        cursor: {batchSize: 0}
    }));
    assert.neq(response.cursor.id, 0);

    stopServerReplication(rst.getSecondary());

    const getMoreResponse = assert.commandFailedWithCode(
        testDB.runCommand({getMore: response.cursor.id, collection: source.getName()}),
        ErrorCodes.WriteConcernFailed);

    // Test the same thing but using the shell helpers.
    let error = assert.throws(
        () => source
                  .aggregate([stageSpec],
                             {cursor: {batchSize: 0}, writeConcern: {w: 2, wtimeout: 100}})
                  .itcount());
    // Unfortunately this is the best way we have to check that the cause of the failure was due
    // to write concern. The aggregate shell helper will assert the command worked. When this
    // fails (as we expect due to write concern) it will create a new error object which loses
    // all structure and just preserves the information as text.
    assert(error instanceof Error);
    assert(tojson(error).indexOf("writeConcernError") != -1, tojson(error));

    // Now test without batchSize just to be sure.
    error =
        assert.throws(() => source.aggregate([stageSpec], {writeConcern: {w: 2, wtimeout: 100}}));
    assert(error instanceof Error);
    assert(tojson(error).indexOf("writeConcernError") != -1, tojson(error));

    // Now switch to legacy OP_GET_MORE read mode. We should get a different error indicating
    // that using writeConcern in this way is unsupported.
    source.getDB().getMongo().forceReadMode("legacy");
    error = assert.throws(
        () => source
                  .aggregate([stageSpec],
                             {cursor: {batchSize: 0}, writeConcern: {w: 2, wtimeout: 100}})
                  .itcount());
    assert.eq(error.code, 31124);
    source.getDB().getMongo().forceReadMode("commands");

    restartServerReplication(rst.getSecondary());
});

rst.stopSet();
}());