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();
}());
|