diff options
author | Charlie Swanson <charlie.swanson@mongodb.com> | 2019-05-17 10:36:51 -0400 |
---|---|---|
committer | Charlie Swanson <charlie.swanson@mongodb.com> | 2019-05-17 10:36:51 -0400 |
commit | 66e7df65d0b2de03448aa26fcb1149f0a0a063ab (patch) | |
tree | b04a791637ecb5a10c0a71d2924598f8ee0bdc99 /jstests/aggregation | |
parent | aa9f6a202e0709adf14046cb27504864adaf732b (diff) | |
download | mongo-66e7df65d0b2de03448aa26fcb1149f0a0a063ab.tar.gz |
SERVER-41201 Add replacement for "withEachOutMode"
Diffstat (limited to 'jstests/aggregation')
-rw-r--r-- | jstests/aggregation/extras/out_helpers.js | 26 | ||||
-rw-r--r-- | jstests/aggregation/sources/explain_out.js | 92 |
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"); }()); |