summaryrefslogtreecommitdiff
path: root/jstests/aggregation
diff options
context:
space:
mode:
authorCharlie Swanson <charlie.swanson@mongodb.com>2019-05-17 10:36:51 -0400
committerCharlie Swanson <charlie.swanson@mongodb.com>2019-05-17 10:36:51 -0400
commit66e7df65d0b2de03448aa26fcb1149f0a0a063ab (patch)
treeb04a791637ecb5a10c0a71d2924598f8ee0bdc99 /jstests/aggregation
parentaa9f6a202e0709adf14046cb27504864adaf732b (diff)
downloadmongo-66e7df65d0b2de03448aa26fcb1149f0a0a063ab.tar.gz
SERVER-41201 Add replacement for "withEachOutMode"
Diffstat (limited to 'jstests/aggregation')
-rw-r--r--jstests/aggregation/extras/out_helpers.js26
-rw-r--r--jstests/aggregation/sources/explain_out.js92
2 files changed, 85 insertions, 33 deletions
diff --git a/jstests/aggregation/extras/out_helpers.js b/jstests/aggregation/extras/out_helpers.js
index 284afaed294..c25e109558d 100644
--- a/jstests/aggregation/extras/out_helpers.js
+++ b/jstests/aggregation/extras/out_helpers.js
@@ -10,6 +10,30 @@ function withEachOutMode(callback) {
callback("replaceDocuments");
}
+/**
+ * Executes the callback function with each valid combination of 'whenMatched' and 'whenNotMatched'
+ * modes (as named arguments). Note that one mode is a pipeline.
+ */
+function withEachMergeMode(callback) {
+ callback({whenMatchedMode: "replaceWithNew", whenNotMatchedMode: "insert"});
+ callback({whenMatchedMode: "replaceWithNew", whenNotMatchedMode: "fail"});
+ // TODO SERVER-40439 callback({whenMatchedMode: "replaceWithNew", whenNotMatchedMode:
+ // "discard"});
+
+ callback({whenMatchedMode: "merge", whenNotMatchedMode: "insert"});
+ callback({whenMatchedMode: "merge", whenNotMatchedMode: "fail"});
+ // TODO SERVER-40439 callback({whenMatchedMode: "merge", whenNotMatchedMode: "discard"});
+
+ callback({whenMatchedMode: "fail", whenNotMatchedMode: "insert"});
+
+ callback({whenMatchedMode: "keepExisting", whenNotMatchedMode: "insert"});
+
+ callback({whenMatchedMode: [], whenNotMatchedMode: "insert"});
+ callback({whenMatchedMode: [], whenNotMatchedMode: "fail"});
+ // TODO SERVER-40439 callback({whenMatchedMode: [{$addFields: {x: 1}}], whenNotMatchedMode:
+ // "discard"});
+}
+
function assertUniqueKeyIsInvalid({source, target, uniqueKey, options, prevStages}) {
withEachOutMode((mode) => {
if (mode === "replaceCollection" && FixtureHelpers.isSharded(target))
@@ -51,4 +75,4 @@ function assertUniqueKeyIsValid({source, target, uniqueKey, options, prevStages}
assert.commandWorked(target.remove({}));
assert.doesNotThrow(() => source.aggregate(pipeline, options));
});
-} \ No newline at end of file
+}
diff --git a/jstests/aggregation/sources/explain_out.js b/jstests/aggregation/sources/explain_out.js
index 9304afcec67..1ef34c53d7d 100644
--- a/jstests/aggregation/sources/explain_out.js
+++ b/jstests/aggregation/sources/explain_out.js
@@ -1,8 +1,8 @@
/**
- * Test aggregation explain of $out pipelines.
+ * Test aggregation explain of $merge and $out pipelines.
*
- * The 'replaceCollection' $out mode is not allowed with a sharded output collection. Explain of
- * $out does not accept writeConcern.
+ * The $out stage is not allowed with a sharded output collection. Explain of $out or $merge does
+ * not accept writeConcern.
* @tags: [assumes_unsharded_collection, assumes_write_concern_unchanged]
*/
(function() {
@@ -12,57 +12,85 @@
load("jstests/libs/analyze_plan.js"); // For getAggPlanStage().
load("jstests/aggregation/extras/out_helpers.js"); // For withEachOutMode().
- let sourceColl = db.explain_out_source;
- let targetColl = db.explain_out_target;
+ let sourceColl = db.explain_writing_aggs_source;
+ let targetColl = db.explain_writing_aggs_target;
sourceColl.drop();
targetColl.drop();
assert.writeOK(sourceColl.insert({_id: 1}));
- function assertQueryPlannerExplainSucceeds(outStage) {
- let explain = sourceColl.explain("queryPlanner").aggregate([outStage]);
- let outExplain = getAggPlanStage(explain, "$out");
- assert.neq(outExplain, null, explain);
- assert.eq(targetColl.find().itcount(), 0, explain);
- return outExplain.$out;
- }
+ // Test that $out can be explained with 'queryPlanner' explain verbosity and does not perform
+ // any writes.
+ let explain = sourceColl.explain("queryPlanner").aggregate([{$out: targetColl.getName()}]);
+ let outExplain = getAggPlanStage(explain, "$out");
+ assert.neq(outExplain, null, explain);
+ // TODO SERVER-40432 $out serialization should never use the 'mode: "replaceCollection"'.
+ assert.eq(outExplain.$out.to, targetColl.getName(), explain);
+ assert.eq(targetColl.find().itcount(), 0, explain);
- // Test each out mode with 'queryPlanner' explain verbosity;
- withEachOutMode(function(outMode) {
- const outStage = {$out: {to: targetColl.getName(), mode: outMode}};
- const explain = sourceColl.explain("queryPlanner").aggregate([outStage]);
- const outExplain = getAggPlanStage(explain, "$out");
- assert.neq(outExplain, null, explain);
- assert(outExplain.hasOwnProperty("$out"), explain);
- assert.eq(outExplain.$out.mode, outMode, outExplain);
- assert.eq(outExplain.$out.uniqueKey, {_id: 1}, outExplain);
+ // Test each $merge mode with 'queryPlanner' explain verbosity.
+ withEachMergeMode(function({whenMatchedMode, whenNotMatchedMode}) {
+ const mergeStage = {
+ $merge: {
+ into: targetColl.getName(),
+ whenMatched: whenMatchedMode,
+ whenNotMatched: whenNotMatchedMode
+ }
+ };
+ const explain = sourceColl.explain("queryPlanner").aggregate([mergeStage]);
+ const mergeExplain = getAggPlanStage(explain, "$merge");
+ assert.neq(mergeExplain, null, explain);
+ assert(mergeExplain.hasOwnProperty("$merge"), explain);
+ assert.eq(mergeExplain.$merge.whenMatched, whenMatchedMode, mergeExplain);
+ assert.eq(mergeExplain.$merge.whenNotMatched, whenNotMatchedMode, mergeExplain);
+ assert.eq(mergeExplain.$merge.on, "_id", mergeExplain);
assert.eq(targetColl.find().itcount(), 0, explain);
});
- function assertExecutionExplainFails(outStage, verbosity) {
+ function assertExecutionExplainFails(writingStage, verbosity) {
assert.commandFailedWithCode(db.runCommand({
- explain: {aggregate: sourceColl.getName(), pipeline: [outStage], cursor: {}},
+ explain: {aggregate: sourceColl.getName(), pipeline: [writingStage], cursor: {}},
verbosity: verbosity
}),
[51029, 51184]);
assert.eq(targetColl.find().itcount(), 0);
}
- // Test that 'executionStats' and 'allPlansExec' level explain fail with each $out mode. These
+ // Test that 'executionStats' and 'allPlansExec' level explain fail with each $merge mode. These
// explain modes must fail, since they would attempt to do writes. Explain must always be
// read-only (including explain of update and delete, which describe what writes they _would_ do
// if exected for real).
- withEachOutMode(function(outMode) {
- const outStage = {$out: {to: targetColl.getName(), mode: outMode}};
- assertExecutionExplainFails(outStage, "executionStats");
- assertExecutionExplainFails(outStage, "allPlansExecution");
+ withEachMergeMode(function({whenMatchedMode, whenNotMatchedMode}) {
+ const mergeStage = {
+ $merge: {
+ into: targetColl.getName(),
+ whenMatched: whenMatchedMode,
+ whenNotMatched: whenNotMatchedMode
+ }
+ };
+ assertExecutionExplainFails(mergeStage, "executionStats");
+ assertExecutionExplainFails(mergeStage, "allPlansExecution");
});
+ // Also test the $out stage since it also performs writes.
+ assertExecutionExplainFails({$out: targetColl.getName()}, "executionStats");
+ assertExecutionExplainFails({$out: targetColl.getName()}, "allPlansExecution");
+
// Execution explain should fail even if the source collection does not exist.
sourceColl.drop();
- withEachOutMode(function(outMode) {
- const outStage = {$out: {to: targetColl.getName(), mode: outMode}};
- assertExecutionExplainFails(outStage, "executionStats");
- assertExecutionExplainFails(outStage, "allPlansExecution");
+ withEachMergeMode(function({whenMatchedMode, whenNotMatchedMode}) {
+ const mergeStage = {
+ $merge: {
+ into: targetColl.getName(),
+ whenMatched: whenMatchedMode,
+ whenNotMatched: whenNotMatchedMode
+ }
+ };
+ assertExecutionExplainFails(mergeStage, "executionStats");
+ assertExecutionExplainFails(mergeStage, "allPlansExecution");
});
+
+ // Also test the $out stage since it also performs writes.
+ assertExecutionExplainFails({$out: targetColl.getName()}, "executionStats");
+ assertExecutionExplainFails({$out: targetColl.getName()}, "allPlansExecution");
}());