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
|
/**
* Tests that a batch size of zero can be used for aggregation commands, and all data can be
* retrieved via getMores.
*/
(function() {
"use strict";
const mongodOptions = {};
const conn = MongoRunner.runMongod(mongodOptions);
assert.neq(null, conn, "mongod failed to start with options " + tojson(mongodOptions));
const testDB = conn.getDB("test");
const coll = testDB[jsTest.name];
coll.drop();
// Test that an aggregate is successful on a non-existent collection.
assert.eq(0,
coll.aggregate([]).toArray().length,
"expected no results from an aggregation on an empty collection");
// Test that an aggregate is successful on a non-existent collection with a batchSize of 0, and
// that a getMore will succeed with an empty result set.
let res = assert.commandWorked(
testDB.runCommand({aggregate: coll.getName(), pipeline: [], cursor: {batchSize: 0}}));
let cursor = new DBCommandCursor(conn, res);
assert.eq(
0, cursor.itcount(), "expected no results from getMore of aggregation on empty collection");
// Test that an aggregation can return *all* matching data via getMores if the initial aggregate
// used a batchSize of 0.
const nDocs = 1000;
const bulk = coll.initializeUnorderedBulkOp();
for (let i = 0; i < nDocs; i++) {
bulk.insert({_id: i, stringField: "string"});
}
assert.writeOK(bulk.execute());
res = assert.commandWorked(
testDB.runCommand({aggregate: coll.getName(), pipeline: [], cursor: {batchSize: 0}}));
cursor = new DBCommandCursor(conn, res);
assert.eq(nDocs, cursor.itcount(), "expected all results to be returned via getMores");
// Test that an error in a getMore will destroy the cursor.
function assertNumOpenCursors(nExpectedOpen) {
let serverStatus = assert.commandWorked(testDB.adminCommand({serverStatus: 1}));
assert.eq(nExpectedOpen,
serverStatus.metrics.cursor.open.total,
"expected to find " + nExpectedOpen + " open cursor(s): " +
tojson(serverStatus.metrics.cursor));
}
// Issue an aggregate command that will fail *at runtime*, so the error will happen in a
// getMore.
assertNumOpenCursors(0);
res = assert.commandWorked(testDB.runCommand({
aggregate: coll.getName(),
pipeline: [{$project: {invalidComputation: {$add: [1, "$stringField"]}}}],
cursor: {batchSize: 0}
}));
cursor = new DBCommandCursor(conn, res);
assertNumOpenCursors(1);
assert.throws(() => cursor.itcount(), [], "expected getMore to fail");
assertNumOpenCursors(0);
// Test that an error in a getMore using a $out stage will destroy the cursor. This test is
// intended to reproduce SERVER-26608.
// Issue an aggregate command that will fail *at runtime*, so the error will happen in a
// getMore.
res = assert.commandWorked(testDB.runCommand({
aggregate: coll.getName(),
pipeline: [{$out: "validated_collection"}],
cursor: {batchSize: 0}
}));
cursor = new DBCommandCursor(conn, res);
assertNumOpenCursors(1);
// Add a document validation rule to the $out collection so that insertion will fail.
assert.commandWorked(testDB.runCommand(
{create: "validated_collection", validator: {stringField: {$type: "int"}}}));
assert.throws(() => cursor.itcount(), [], "expected getMore to fail");
assertNumOpenCursors(0);
}());
|