summaryrefslogtreecommitdiff
path: root/src/mongo/dbtests/pipelinetests.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/dbtests/pipelinetests.cpp')
-rw-r--r--src/mongo/dbtests/pipelinetests.cpp747
1 files changed, 392 insertions, 355 deletions
diff --git a/src/mongo/dbtests/pipelinetests.cpp b/src/mongo/dbtests/pipelinetests.cpp
index f97bf9217a9..e8b54eeea76 100644
--- a/src/mongo/dbtests/pipelinetests.cpp
+++ b/src/mongo/dbtests/pipelinetests.cpp
@@ -39,358 +39,395 @@
namespace PipelineTests {
- using boost::intrusive_ptr;
- using std::string;
-
- namespace Optimizations {
- using namespace mongo;
-
- namespace Local {
- class Base {
- public:
- // These both return json arrays of pipeline operators
- virtual string inputPipeJson() = 0;
- virtual string outputPipeJson() = 0;
-
- BSONObj pipelineFromJsonArray(const string& array) {
- return fromjson("{pipeline: " + array + "}");
- }
- virtual void run() {
- const BSONObj inputBson = pipelineFromJsonArray(inputPipeJson());
- const BSONObj outputPipeExpected = pipelineFromJsonArray(outputPipeJson());
-
- intrusive_ptr<ExpressionContext> ctx =
- new ExpressionContext(&_opCtx, NamespaceString("a.collection"));
- string errmsg;
- intrusive_ptr<Pipeline> outputPipe =
- Pipeline::parseCommand(errmsg, inputBson, ctx);
- ASSERT_EQUALS(errmsg, "");
- ASSERT(outputPipe != NULL);
-
- ASSERT_EQUALS(Value(outputPipe->writeExplainOps()),
- Value(outputPipeExpected["pipeline"]));
- }
-
- virtual ~Base() {}
-
- private:
- OperationContextImpl _opCtx;
- };
-
- class MoveSkipBeforeProject: public Base {
- string inputPipeJson() override {
- return "[{$project: {a : 1}}, {$skip : 5}]";
- }
-
- string outputPipeJson() override {
- return "[{$skip : 5}, {$project: {a : true}}]";
- }
- };
-
- class MoveLimitBeforeProject: public Base {
- string inputPipeJson() override {
- return "[{$project: {a : 1}}, {$limit : 5}]";
- }
-
- string outputPipeJson() override {
- return "[{$limit : 5}, {$project: {a : true}}]";
- }
- };
-
- class MoveMulitipleSkipsAndLimitsBeforeProject: public Base {
- string inputPipeJson() override {
- return "[{$project: {a : 1}}, {$limit : 5}, {$skip : 3}]";
- }
-
- string outputPipeJson() override {
- return "[{$limit : 5}, {$skip : 3}, {$project: {a : true}}]";
- }
- };
-
- class SortMatchProjSkipLimBecomesMatchTopKSortSkipProj: public Base {
- string inputPipeJson() override {
- return "[{$sort: {a: 1}}"
- ",{$match: {a: 1}}"
- ",{$project : {a: 1}}"
- ",{$skip : 3}"
- ",{$limit: 5}"
- "]";
- }
-
- string outputPipeJson() override {
- return "[{$match: {a: 1}}"
- ",{$sort: {sortKey: {a: 1}, limit: 8}}"
- ",{$skip: 3}"
- ",{$project: {a: true}}"
- "]";
- }
- };
-
- class RemoveSkipZero : public Base {
- string inputPipeJson() override {
- return "[{$skip: 0}]";
- }
-
- string outputPipeJson() override {
- return "[]";
- }
- };
-
- class DoNotRemoveSkipOne : public Base {
- string inputPipeJson() override {
- return "[{$skip: 1}]";
- }
-
- string outputPipeJson() override {
- return "[{$skip: 1}]";
- }
- };
-
- class RemoveEmptyMatch : public Base {
- string inputPipeJson() override {
- return "[{$match: {}}]";
- }
-
- string outputPipeJson() override {
- return "[]";
- }
- };
-
- class RemoveMultipleEmptyMatches : public Base {
- string inputPipeJson() override {
- return "[{$match: {}}, {$match: {}}]";
- }
-
- string outputPipeJson() override {
- // TODO: The desired behavior here is to end up with an empty array.
- return "[{$match: {$and: [{}, {}]}}]";
- }
- };
-
- class DoNotRemoveNonEmptyMatch : public Base {
- string inputPipeJson() override {
- return "[{$match: {_id: 1}}]";
- }
-
- string outputPipeJson() override {
- return "[{$match: {_id: 1}}]";
- }
- };
-
- } // namespace Local
-
- namespace Sharded {
- class Base {
- public:
- // These all return json arrays of pipeline operators
- virtual string inputPipeJson() = 0;
- virtual string shardPipeJson() = 0;
- virtual string mergePipeJson() = 0;
-
- BSONObj pipelineFromJsonArray(const string& array) {
- return fromjson("{pipeline: " + array + "}");
- }
- virtual void run() {
- const BSONObj inputBson = pipelineFromJsonArray(inputPipeJson());
- const BSONObj shardPipeExpected = pipelineFromJsonArray(shardPipeJson());
- const BSONObj mergePipeExpected = pipelineFromJsonArray(mergePipeJson());
-
- intrusive_ptr<ExpressionContext> ctx =
- new ExpressionContext(&_opCtx, NamespaceString("a.collection"));
- string errmsg;
- intrusive_ptr<Pipeline> mergePipe =
- Pipeline::parseCommand(errmsg, inputBson, ctx);
- ASSERT_EQUALS(errmsg, "");
- ASSERT(mergePipe != NULL);
-
- intrusive_ptr<Pipeline> shardPipe = mergePipe->splitForSharded();
- ASSERT(shardPipe != NULL);
-
- ASSERT_EQUALS(Value(shardPipe->writeExplainOps()),
- Value(shardPipeExpected["pipeline"]));
- ASSERT_EQUALS(Value(mergePipe->writeExplainOps()),
- Value(mergePipeExpected["pipeline"]));
- }
-
- virtual ~Base() {}
-
- private:
- OperationContextImpl _opCtx;
- };
-
- // General test to make sure all optimizations support empty pipelines
- class Empty : public Base {
- string inputPipeJson() { return "[]"; }
- string shardPipeJson() { return "[]"; }
- string mergePipeJson() { return "[]"; }
- };
-
- namespace moveFinalUnwindFromShardsToMerger {
-
- class OneUnwind : public Base {
- string inputPipeJson() { return "[{$unwind: '$a'}]}"; }
- string shardPipeJson() { return "[]}"; }
- string mergePipeJson() { return "[{$unwind: '$a'}]}"; }
- };
-
- class TwoUnwind : public Base {
- string inputPipeJson() { return "[{$unwind: '$a'}, {$unwind: '$b'}]}"; }
- string shardPipeJson() { return "[]}"; }
- string mergePipeJson() { return "[{$unwind: '$a'}, {$unwind: '$b'}]}"; }
- };
-
- class UnwindNotFinal : public Base {
- string inputPipeJson() { return "[{$unwind: '$a'}, {$match: {a:1}}]}"; }
- string shardPipeJson() { return "[{$unwind: '$a'}, {$match: {a:1}}]}"; }
- string mergePipeJson() { return "[]}"; }
- };
-
- class UnwindWithOther : public Base {
- string inputPipeJson() { return "[{$match: {a:1}}, {$unwind: '$a'}]}"; }
- string shardPipeJson() { return "[{$match: {a:1}}]}"; }
- string mergePipeJson() { return "[{$unwind: '$a'}]}"; }
- };
- } // namespace moveFinalUnwindFromShardsToMerger
-
-
- namespace limitFieldsSentFromShardsToMerger {
- // These tests use $limit to split the pipelines between shards and merger as it is
- // always a split point and neutral in terms of needed fields.
-
- class NeedWholeDoc : public Base {
- string inputPipeJson() { return "[{$limit:1}]"; }
- string shardPipeJson() { return "[{$limit:1}]"; }
- string mergePipeJson() { return "[{$limit:1}]"; }
- };
-
- class JustNeedsId : public Base {
- string inputPipeJson() { return "[{$limit:1}, {$group: {_id: '$_id'}}]"; }
- string shardPipeJson() { return "[{$limit:1}, {$project: {_id:true}}]"; }
- string mergePipeJson() { return "[{$limit:1}, {$group: {_id: '$_id'}}]"; }
- };
-
- class JustNeedsNonId : public Base {
- string inputPipeJson() {
- return "[{$limit:1}, {$group: {_id: '$a.b'}}]";
- }
- string shardPipeJson() {
- return "[{$limit:1}, {$project: {_id: false, a: {b: true}}}]";
- }
- string mergePipeJson() {
- return "[{$limit:1}, {$group: {_id: '$a.b'}}]";
- }
- };
-
- class NothingNeeded : public Base {
- string inputPipeJson() {
- return "[{$limit:1}"
- ",{$group: {_id: {$const: null}, count: {$sum: {$const: 1}}}}"
- "]";
- }
- string shardPipeJson() {
- return "[{$limit:1}"
- ",{$project: {_id: true}}"
- "]";
- }
- string mergePipeJson() {
- return "[{$limit:1}"
- ",{$group: {_id: {$const: null}, count: {$sum: {$const: 1}}}}"
- "]";
- }
- };
-
- class JustNeedsMetadata : public Base {
- // Currently this optimization doesn't handle metadata and the shards assume it
- // needs to be propagated implicitly. Therefore the $project produced should be
- // the same as in NothingNeeded.
- string inputPipeJson() {
- return "[{$limit:1}, {$project: {_id: false, a: {$meta: 'textScore'}}}]";
- }
- string shardPipeJson() {
- return "[{$limit:1}, {$project: {_id: true}}]";
- }
- string mergePipeJson() {
- return "[{$limit:1}, {$project: {_id: false, a: {$meta: 'textScore'}}}]";
- }
- };
-
- class ShardAlreadyExhaustive : public Base {
- // No new project should be added. This test reflects current behavior where the
- // 'a' field is still sent because it is explicitly asked for, even though it
- // isn't actually needed. If this changes in the future, this test will need to
- // change.
- string inputPipeJson() {
- return "[{$project: {_id:true, a:true}}"
- ",{$group: {_id: '$_id'}}"
- "]";
- }
- string shardPipeJson() {
- return "[{$project: {_id:true, a:true}}"
- ",{$group: {_id: '$_id'}}"
- "]";
- }
- string mergePipeJson() {
- return "[{$group: {_id: '$$ROOT._id', $doingMerge: true}}"
- "]";
- }
- };
-
- class ShardedSortMatchProjSkipLimBecomesMatchTopKSortSkipProj: public Base {
- string inputPipeJson() {
- return "[{$sort: {a : 1}}"
- ",{$match: {a: 1}}"
- ",{$project : {a: 1}}"
- ",{$skip : 3}"
- ",{$limit: 5}"
- "]";
- }
- string shardPipeJson() {
- return "[{$match: {a: 1}}"
- ",{$sort: {sortKey: {a: 1}, limit: 8}}"
- ",{$project: {a: true, _id: true}}"
- "]";
- }
- string mergePipeJson() {
- return "[{$sort: {sortKey: {a: 1}, mergePresorted: true, limit: 8}}"
- ",{$skip: 3}"
- ",{$project: {a: true}}"
- "]";
- }
- };
-
- } // namespace limitFieldsSentFromShardsToMerger
- } // namespace Sharded
- } // namespace Optimizations
-
- class All : public Suite {
- public:
- All() : Suite( "pipeline" ) {
- }
- void setupTests() {
- add<Optimizations::Local::RemoveSkipZero>();
- add<Optimizations::Local::MoveLimitBeforeProject>();
- add<Optimizations::Local::MoveSkipBeforeProject>();
- add<Optimizations::Local::MoveMulitipleSkipsAndLimitsBeforeProject>();
- add<Optimizations::Local::SortMatchProjSkipLimBecomesMatchTopKSortSkipProj>();
- add<Optimizations::Local::DoNotRemoveSkipOne>();
- add<Optimizations::Local::RemoveEmptyMatch>();
- add<Optimizations::Local::RemoveMultipleEmptyMatches>();
- add<Optimizations::Local::DoNotRemoveNonEmptyMatch>();
- add<Optimizations::Sharded::Empty>();
- add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::OneUnwind>();
- add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::TwoUnwind>();
- add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::UnwindNotFinal>();
- add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::UnwindWithOther>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::NeedWholeDoc>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsId>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsNonId>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::NothingNeeded>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsMetadata>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::ShardAlreadyExhaustive>();
- add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::ShardedSortMatchProjSkipLimBecomesMatchTopKSortSkipProj>();
- }
- };
-
- SuiteInstance<All> myall;
-
-} // namespace PipelineTests
+using boost::intrusive_ptr;
+using std::string;
+
+namespace Optimizations {
+using namespace mongo;
+
+namespace Local {
+class Base {
+public:
+ // These both return json arrays of pipeline operators
+ virtual string inputPipeJson() = 0;
+ virtual string outputPipeJson() = 0;
+
+ BSONObj pipelineFromJsonArray(const string& array) {
+ return fromjson("{pipeline: " + array + "}");
+ }
+ virtual void run() {
+ const BSONObj inputBson = pipelineFromJsonArray(inputPipeJson());
+ const BSONObj outputPipeExpected = pipelineFromJsonArray(outputPipeJson());
+
+ intrusive_ptr<ExpressionContext> ctx =
+ new ExpressionContext(&_opCtx, NamespaceString("a.collection"));
+ string errmsg;
+ intrusive_ptr<Pipeline> outputPipe = Pipeline::parseCommand(errmsg, inputBson, ctx);
+ ASSERT_EQUALS(errmsg, "");
+ ASSERT(outputPipe != NULL);
+
+ ASSERT_EQUALS(Value(outputPipe->writeExplainOps()), Value(outputPipeExpected["pipeline"]));
+ }
+
+ virtual ~Base() {}
+
+private:
+ OperationContextImpl _opCtx;
+};
+
+class MoveSkipBeforeProject : public Base {
+ string inputPipeJson() override {
+ return "[{$project: {a : 1}}, {$skip : 5}]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$skip : 5}, {$project: {a : true}}]";
+ }
+};
+
+class MoveLimitBeforeProject : public Base {
+ string inputPipeJson() override {
+ return "[{$project: {a : 1}}, {$limit : 5}]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$limit : 5}, {$project: {a : true}}]";
+ }
+};
+
+class MoveMulitipleSkipsAndLimitsBeforeProject : public Base {
+ string inputPipeJson() override {
+ return "[{$project: {a : 1}}, {$limit : 5}, {$skip : 3}]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$limit : 5}, {$skip : 3}, {$project: {a : true}}]";
+ }
+};
+
+class SortMatchProjSkipLimBecomesMatchTopKSortSkipProj : public Base {
+ string inputPipeJson() override {
+ return "[{$sort: {a: 1}}"
+ ",{$match: {a: 1}}"
+ ",{$project : {a: 1}}"
+ ",{$skip : 3}"
+ ",{$limit: 5}"
+ "]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$match: {a: 1}}"
+ ",{$sort: {sortKey: {a: 1}, limit: 8}}"
+ ",{$skip: 3}"
+ ",{$project: {a: true}}"
+ "]";
+ }
+};
+
+class RemoveSkipZero : public Base {
+ string inputPipeJson() override {
+ return "[{$skip: 0}]";
+ }
+
+ string outputPipeJson() override {
+ return "[]";
+ }
+};
+
+class DoNotRemoveSkipOne : public Base {
+ string inputPipeJson() override {
+ return "[{$skip: 1}]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$skip: 1}]";
+ }
+};
+
+class RemoveEmptyMatch : public Base {
+ string inputPipeJson() override {
+ return "[{$match: {}}]";
+ }
+
+ string outputPipeJson() override {
+ return "[]";
+ }
+};
+
+class RemoveMultipleEmptyMatches : public Base {
+ string inputPipeJson() override {
+ return "[{$match: {}}, {$match: {}}]";
+ }
+
+ string outputPipeJson() override {
+ // TODO: The desired behavior here is to end up with an empty array.
+ return "[{$match: {$and: [{}, {}]}}]";
+ }
+};
+
+class DoNotRemoveNonEmptyMatch : public Base {
+ string inputPipeJson() override {
+ return "[{$match: {_id: 1}}]";
+ }
+
+ string outputPipeJson() override {
+ return "[{$match: {_id: 1}}]";
+ }
+};
+
+} // namespace Local
+
+namespace Sharded {
+class Base {
+public:
+ // These all return json arrays of pipeline operators
+ virtual string inputPipeJson() = 0;
+ virtual string shardPipeJson() = 0;
+ virtual string mergePipeJson() = 0;
+
+ BSONObj pipelineFromJsonArray(const string& array) {
+ return fromjson("{pipeline: " + array + "}");
+ }
+ virtual void run() {
+ const BSONObj inputBson = pipelineFromJsonArray(inputPipeJson());
+ const BSONObj shardPipeExpected = pipelineFromJsonArray(shardPipeJson());
+ const BSONObj mergePipeExpected = pipelineFromJsonArray(mergePipeJson());
+
+ intrusive_ptr<ExpressionContext> ctx =
+ new ExpressionContext(&_opCtx, NamespaceString("a.collection"));
+ string errmsg;
+ intrusive_ptr<Pipeline> mergePipe = Pipeline::parseCommand(errmsg, inputBson, ctx);
+ ASSERT_EQUALS(errmsg, "");
+ ASSERT(mergePipe != NULL);
+
+ intrusive_ptr<Pipeline> shardPipe = mergePipe->splitForSharded();
+ ASSERT(shardPipe != NULL);
+
+ ASSERT_EQUALS(Value(shardPipe->writeExplainOps()), Value(shardPipeExpected["pipeline"]));
+ ASSERT_EQUALS(Value(mergePipe->writeExplainOps()), Value(mergePipeExpected["pipeline"]));
+ }
+
+ virtual ~Base() {}
+
+private:
+ OperationContextImpl _opCtx;
+};
+
+// General test to make sure all optimizations support empty pipelines
+class Empty : public Base {
+ string inputPipeJson() {
+ return "[]";
+ }
+ string shardPipeJson() {
+ return "[]";
+ }
+ string mergePipeJson() {
+ return "[]";
+ }
+};
+
+namespace moveFinalUnwindFromShardsToMerger {
+
+class OneUnwind : public Base {
+ string inputPipeJson() {
+ return "[{$unwind: '$a'}]}";
+ }
+ string shardPipeJson() {
+ return "[]}";
+ }
+ string mergePipeJson() {
+ return "[{$unwind: '$a'}]}";
+ }
+};
+
+class TwoUnwind : public Base {
+ string inputPipeJson() {
+ return "[{$unwind: '$a'}, {$unwind: '$b'}]}";
+ }
+ string shardPipeJson() {
+ return "[]}";
+ }
+ string mergePipeJson() {
+ return "[{$unwind: '$a'}, {$unwind: '$b'}]}";
+ }
+};
+
+class UnwindNotFinal : public Base {
+ string inputPipeJson() {
+ return "[{$unwind: '$a'}, {$match: {a:1}}]}";
+ }
+ string shardPipeJson() {
+ return "[{$unwind: '$a'}, {$match: {a:1}}]}";
+ }
+ string mergePipeJson() {
+ return "[]}";
+ }
+};
+
+class UnwindWithOther : public Base {
+ string inputPipeJson() {
+ return "[{$match: {a:1}}, {$unwind: '$a'}]}";
+ }
+ string shardPipeJson() {
+ return "[{$match: {a:1}}]}";
+ }
+ string mergePipeJson() {
+ return "[{$unwind: '$a'}]}";
+ }
+};
+} // namespace moveFinalUnwindFromShardsToMerger
+
+
+namespace limitFieldsSentFromShardsToMerger {
+// These tests use $limit to split the pipelines between shards and merger as it is
+// always a split point and neutral in terms of needed fields.
+
+class NeedWholeDoc : public Base {
+ string inputPipeJson() {
+ return "[{$limit:1}]";
+ }
+ string shardPipeJson() {
+ return "[{$limit:1}]";
+ }
+ string mergePipeJson() {
+ return "[{$limit:1}]";
+ }
+};
+
+class JustNeedsId : public Base {
+ string inputPipeJson() {
+ return "[{$limit:1}, {$group: {_id: '$_id'}}]";
+ }
+ string shardPipeJson() {
+ return "[{$limit:1}, {$project: {_id:true}}]";
+ }
+ string mergePipeJson() {
+ return "[{$limit:1}, {$group: {_id: '$_id'}}]";
+ }
+};
+
+class JustNeedsNonId : public Base {
+ string inputPipeJson() {
+ return "[{$limit:1}, {$group: {_id: '$a.b'}}]";
+ }
+ string shardPipeJson() {
+ return "[{$limit:1}, {$project: {_id: false, a: {b: true}}}]";
+ }
+ string mergePipeJson() {
+ return "[{$limit:1}, {$group: {_id: '$a.b'}}]";
+ }
+};
+
+class NothingNeeded : public Base {
+ string inputPipeJson() {
+ return "[{$limit:1}"
+ ",{$group: {_id: {$const: null}, count: {$sum: {$const: 1}}}}"
+ "]";
+ }
+ string shardPipeJson() {
+ return "[{$limit:1}"
+ ",{$project: {_id: true}}"
+ "]";
+ }
+ string mergePipeJson() {
+ return "[{$limit:1}"
+ ",{$group: {_id: {$const: null}, count: {$sum: {$const: 1}}}}"
+ "]";
+ }
+};
+
+class JustNeedsMetadata : public Base {
+ // Currently this optimization doesn't handle metadata and the shards assume it
+ // needs to be propagated implicitly. Therefore the $project produced should be
+ // the same as in NothingNeeded.
+ string inputPipeJson() {
+ return "[{$limit:1}, {$project: {_id: false, a: {$meta: 'textScore'}}}]";
+ }
+ string shardPipeJson() {
+ return "[{$limit:1}, {$project: {_id: true}}]";
+ }
+ string mergePipeJson() {
+ return "[{$limit:1}, {$project: {_id: false, a: {$meta: 'textScore'}}}]";
+ }
+};
+
+class ShardAlreadyExhaustive : public Base {
+ // No new project should be added. This test reflects current behavior where the
+ // 'a' field is still sent because it is explicitly asked for, even though it
+ // isn't actually needed. If this changes in the future, this test will need to
+ // change.
+ string inputPipeJson() {
+ return "[{$project: {_id:true, a:true}}"
+ ",{$group: {_id: '$_id'}}"
+ "]";
+ }
+ string shardPipeJson() {
+ return "[{$project: {_id:true, a:true}}"
+ ",{$group: {_id: '$_id'}}"
+ "]";
+ }
+ string mergePipeJson() {
+ return "[{$group: {_id: '$$ROOT._id', $doingMerge: true}}"
+ "]";
+ }
+};
+
+class ShardedSortMatchProjSkipLimBecomesMatchTopKSortSkipProj : public Base {
+ string inputPipeJson() {
+ return "[{$sort: {a : 1}}"
+ ",{$match: {a: 1}}"
+ ",{$project : {a: 1}}"
+ ",{$skip : 3}"
+ ",{$limit: 5}"
+ "]";
+ }
+ string shardPipeJson() {
+ return "[{$match: {a: 1}}"
+ ",{$sort: {sortKey: {a: 1}, limit: 8}}"
+ ",{$project: {a: true, _id: true}}"
+ "]";
+ }
+ string mergePipeJson() {
+ return "[{$sort: {sortKey: {a: 1}, mergePresorted: true, limit: 8}}"
+ ",{$skip: 3}"
+ ",{$project: {a: true}}"
+ "]";
+ }
+};
+
+} // namespace limitFieldsSentFromShardsToMerger
+} // namespace Sharded
+} // namespace Optimizations
+
+class All : public Suite {
+public:
+ All() : Suite("pipeline") {}
+ void setupTests() {
+ add<Optimizations::Local::RemoveSkipZero>();
+ add<Optimizations::Local::MoveLimitBeforeProject>();
+ add<Optimizations::Local::MoveSkipBeforeProject>();
+ add<Optimizations::Local::MoveMulitipleSkipsAndLimitsBeforeProject>();
+ add<Optimizations::Local::SortMatchProjSkipLimBecomesMatchTopKSortSkipProj>();
+ add<Optimizations::Local::DoNotRemoveSkipOne>();
+ add<Optimizations::Local::RemoveEmptyMatch>();
+ add<Optimizations::Local::RemoveMultipleEmptyMatches>();
+ add<Optimizations::Local::DoNotRemoveNonEmptyMatch>();
+ add<Optimizations::Sharded::Empty>();
+ add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::OneUnwind>();
+ add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::TwoUnwind>();
+ add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::UnwindNotFinal>();
+ add<Optimizations::Sharded::moveFinalUnwindFromShardsToMerger::UnwindWithOther>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::NeedWholeDoc>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsId>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsNonId>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::NothingNeeded>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::JustNeedsMetadata>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::ShardAlreadyExhaustive>();
+ add<Optimizations::Sharded::limitFieldsSentFromShardsToMerger::
+ ShardedSortMatchProjSkipLimBecomesMatchTopKSortSkipProj>();
+ }
+};
+
+SuiteInstance<All> myall;
+
+} // namespace PipelineTests