summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/document_source_lookup_test.cpp
diff options
context:
space:
mode:
authorCharlie Swanson <charlie.swanson@mongodb.com>2020-01-09 12:34:47 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-13 03:13:43 +0000
commit70258e4babfcfa3725a4bf9cf06e853632917e57 (patch)
treec077f63382b148844d88805888b2c87c2d2676af /src/mongo/db/pipeline/document_source_lookup_test.cpp
parent66002c604a9a2cd9c419bad318db0252f576dbd8 (diff)
downloadmongo-70258e4babfcfa3725a4bf9cf06e853632917e57.tar.gz
SERVER-45465 Add support for storing $unionWith in a view (unsharded)
Diffstat (limited to 'src/mongo/db/pipeline/document_source_lookup_test.cpp')
-rw-r--r--src/mongo/db/pipeline/document_source_lookup_test.cpp122
1 files changed, 51 insertions, 71 deletions
diff --git a/src/mongo/db/pipeline/document_source_lookup_test.cpp b/src/mongo/db/pipeline/document_source_lookup_test.cpp
index ae0f329e14f..e6c4e9e93f5 100644
--- a/src/mongo/db/pipeline/document_source_lookup_test.cpp
+++ b/src/mongo/db/pipeline/document_source_lookup_test.cpp
@@ -220,7 +220,7 @@ TEST_F(DocumentSourceLookUpTest, RejectLookupWhenDepthLimitIsExceeded) {
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
- expCtx->subPipelineDepth = DocumentSourceLookUp::kMaxSubPipelineDepth;
+ expCtx->subPipelineDepth = ExpressionContext::kMaxSubPipelineViewDepth;
ASSERT_THROWS_CODE(
DocumentSourceLookUp::createFromBson(
@@ -493,23 +493,6 @@ public:
return false;
}
- std::unique_ptr<Pipeline, PipelineDeleter> makePipeline(
- const std::vector<BSONObj>& rawPipeline,
- const boost::intrusive_ptr<ExpressionContext>& expCtx,
- const MakePipelineOptions opts) final {
- auto pipeline = uassertStatusOK(Pipeline::parse(rawPipeline, expCtx));
-
- if (opts.optimize) {
- pipeline->optimizePipeline();
- }
-
- if (opts.attachCursorSource) {
- pipeline = attachCursorSourceToPipeline(expCtx, pipeline.release(), false);
- }
-
- return pipeline;
- }
-
std::unique_ptr<Pipeline, PipelineDeleter> attachCursorSourceToPipeline(
const boost::intrusive_ptr<ExpressionContext>& expCtx,
Pipeline* ownedPipeline,
@@ -540,31 +523,31 @@ TEST_F(DocumentSourceLookUpTest, ShouldPropagatePauses) {
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
- // Set up the $lookup stage.
- auto lookupSpec = Document{{"$lookup",
- Document{{"from", fromNs.coll()},
- {"localField", "foreignId"_sd},
- {"foreignField", "_id"_sd},
- {"as", "foreignDocs"_sd}}}}
- .toBson();
- auto parsed = DocumentSourceLookUp::createFromBson(lookupSpec.firstElement(), expCtx);
- auto lookup = static_cast<DocumentSourceLookUp*>(parsed.get());
-
- // Mock its input, pausing every other result.
+ // Mock the input of a foreign namespace, pausing every other result.
auto mockLocalSource =
DocumentSourceMock::createForTest({Document{{"foreignId", 0}},
DocumentSource::GetNextResult::makePauseExecution(),
Document{{"foreignId", 1}},
DocumentSource::GetNextResult::makePauseExecution()});
- lookup->setSource(mockLocalSource.get());
-
// Mock out the foreign collection.
deque<DocumentSource::GetNextResult> mockForeignContents{Document{{"_id", 0}},
Document{{"_id", 1}}};
expCtx->mongoProcessInterface =
std::make_shared<MockMongoInterface>(std::move(mockForeignContents));
+ // Set up the $lookup stage.
+ auto lookupSpec = Document{{"$lookup",
+ Document{{"from", fromNs.coll()},
+ {"localField", "foreignId"_sd},
+ {"foreignField", "_id"_sd},
+ {"as", "foreignDocs"_sd}}}}
+ .toBson();
+ auto parsed = DocumentSourceLookUp::createFromBson(lookupSpec.firstElement(), expCtx);
+ auto lookup = static_cast<DocumentSourceLookUp*>(parsed.get());
+
+ lookup->setSource(mockLocalSource.get());
+
auto next = lookup->getNext();
ASSERT_TRUE(next.isAdvanced());
ASSERT_DOCUMENT_EQ(
@@ -592,6 +575,12 @@ TEST_F(DocumentSourceLookUpTest, ShouldPropagatePausesWhileUnwinding) {
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ // Mock out the foreign collection.
+ deque<DocumentSource::GetNextResult> mockForeignContents{Document{{"_id", 0}},
+ Document{{"_id", 1}}};
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::move(mockForeignContents));
+
// Set up the $lookup stage.
auto lookupSpec = Document{{"$lookup",
Document{{"from", fromNs.coll()},
@@ -615,12 +604,6 @@ TEST_F(DocumentSourceLookUpTest, ShouldPropagatePausesWhileUnwinding) {
DocumentSource::GetNextResult::makePauseExecution()});
lookup->setSource(mockLocalSource.get());
- // Mock out the foreign collection.
- deque<DocumentSource::GetNextResult> mockForeignContents{Document{{"_id", 0}},
- Document{{"_id", 1}}};
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::move(mockForeignContents));
-
auto next = lookup->getNext();
ASSERT_TRUE(next.isAdvanced());
ASSERT_DOCUMENT_EQ(next.releaseDocument(),
@@ -703,6 +686,9 @@ TEST_F(DocumentSourceLookUpTest, ShouldCacheNonCorrelatedSubPipelinePrefix) {
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
auto docSource = DocumentSourceLookUp::createFromBson(
fromjson("{$lookup: {let: {var1: '$_id'}, pipeline: [{$match: {x:1}}, {$sort: {x: 1}}, "
"{$addFields: {varField: '$$var1'}}], from: 'coll', as: 'as'}}")
@@ -712,9 +698,6 @@ TEST_F(DocumentSourceLookUpTest, ShouldCacheNonCorrelatedSubPipelinePrefix) {
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -732,6 +715,9 @@ TEST_F(DocumentSourceLookUpTest,
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
// In the $facet stage here, the correlated $match stage comes after a $group stage which
// returns EXHAUSTIVE_ALL for its dependencies. Verify that we continue enumerating the $facet
// pipeline's variable dependencies after this point, so that the $facet stage is correctly
@@ -746,9 +732,6 @@ TEST_F(DocumentSourceLookUpTest,
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -768,6 +751,9 @@ TEST_F(DocumentSourceLookUpTest, ExprEmbeddedInMatchExpressionShouldBeOptimized)
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
// This pipeline includes a $match stage that itself includes a $expr expression.
auto docSource = DocumentSourceLookUp::createFromBson(
fromjson("{$lookup: {let: {var1: '$_id'}, pipeline: [{$match: {$expr: {$eq: "
@@ -778,9 +764,6 @@ TEST_F(DocumentSourceLookUpTest, ExprEmbeddedInMatchExpressionShouldBeOptimized)
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -808,6 +791,9 @@ TEST_F(DocumentSourceLookUpTest,
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
// The $project stage defines a local variable with the same name as the $lookup 'let' variable.
// Verify that the $project is identified as non-correlated and the cache is placed after it.
auto docSource = DocumentSourceLookUp::createFromBson(
@@ -822,9 +808,6 @@ TEST_F(DocumentSourceLookUpTest,
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -844,6 +827,9 @@ TEST_F(DocumentSourceLookUpTest, ShouldInsertCacheBeforeCorrelatedNestedLookup)
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
// Create a $lookup stage whose pipeline contains nested $lookups. The third-level $lookup
// refers to a 'let' variable defined in the top-level $lookup. Verify that the second-level
// $lookup is correctly identified as a correlated stage and the cache is placed before it.
@@ -858,9 +844,6 @@ TEST_F(DocumentSourceLookUpTest, ShouldInsertCacheBeforeCorrelatedNestedLookup)
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -882,6 +865,9 @@ TEST_F(DocumentSourceLookUpTest,
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ expCtx->mongoProcessInterface =
+ std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
+
// The nested $lookup stage defines a 'let' variable with the same name as the top-level 'let'.
// Verify the nested $lookup is identified as non-correlated and the cache is placed after it.
auto docSource = DocumentSourceLookUp::createFromBson(
@@ -895,9 +881,6 @@ TEST_F(DocumentSourceLookUpTest,
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- expCtx->mongoProcessInterface =
- std::make_shared<MockMongoInterface>(std::deque<DocumentSource::GetNextResult>{});
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 5));
ASSERT(subPipeline);
@@ -949,6 +932,10 @@ TEST_F(DocumentSourceLookUpTest,
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ deque<DocumentSource::GetNextResult> mockForeignContents{
+ Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}};
+ expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(mockForeignContents);
+
auto docSource = DocumentSourceLookUp::createFromBson(
fromjson(
"{$lookup: {let: {var1: '$_id'}, pipeline: [{$match: {x: {$gte: 0}}}, {$sort: {x: "
@@ -959,17 +946,12 @@ TEST_F(DocumentSourceLookUpTest,
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- // Prepare the mocked local and foreign sources.
+ // Prepare the mocked local source.
auto mockLocalSource = DocumentSourceMock::createForTest(
{Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}});
lookupStage->setSource(mockLocalSource.get());
- deque<DocumentSource::GetNextResult> mockForeignContents{
- Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}};
-
- expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(mockForeignContents);
-
// Confirm that the empty 'kBuilding' cache is placed just before the correlated $addFields.
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 0));
ASSERT(subPipeline);
@@ -1024,6 +1006,10 @@ TEST_F(DocumentSourceLookUpTest,
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ deque<DocumentSource::GetNextResult> mockForeignContents{Document{{"x", 0}},
+ Document{{"x", 1}}};
+ expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(mockForeignContents);
+
// Ensure the cache is abandoned after the first iteration by setting its max size to 0.
size_t maxCacheSizeBytes = 0;
auto docSource = DocumentSourceLookUp::createFromBsonWithCacheSize(
@@ -1043,11 +1029,6 @@ TEST_F(DocumentSourceLookUpTest,
lookupStage->setSource(mockLocalSource.get());
- deque<DocumentSource::GetNextResult> mockForeignContents{Document{{"x", 0}},
- Document{{"x", 1}}};
-
- expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(mockForeignContents);
-
// Confirm that the empty 'kBuilding' cache is placed just before the correlated $addFields.
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 0));
ASSERT(subPipeline);
@@ -1091,6 +1072,10 @@ TEST_F(DocumentSourceLookUpTest, ShouldNotCacheIfCorrelatedStageIsAbsorbedIntoPl
expCtx->setResolvedNamespaces(StringMap<ExpressionContext::ResolvedNamespace>{
{fromNs.coll().toString(), {fromNs, std::vector<BSONObj>()}}});
+ const bool removeLeadingQueryStages = true;
+ expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(
+ std::deque<DocumentSource::GetNextResult>{}, removeLeadingQueryStages);
+
auto docSource = DocumentSourceLookUp::createFromBson(
fromjson("{$lookup: {let: {var1: '$_id'}, pipeline: [{$match: {$expr: { $gte: ['$x', "
"'$$var1']}}}, {$sort: {x: 1}}, {$addFields: {varField: {$sum: ['$x', "
@@ -1101,11 +1086,6 @@ TEST_F(DocumentSourceLookUpTest, ShouldNotCacheIfCorrelatedStageIsAbsorbedIntoPl
auto lookupStage = static_cast<DocumentSourceLookUp*>(docSource.get());
ASSERT(lookupStage);
- const bool removeLeadingQueryStages = true;
-
- expCtx->mongoProcessInterface = std::make_shared<MockMongoInterface>(
- std::deque<DocumentSource::GetNextResult>{}, removeLeadingQueryStages);
-
auto subPipeline = lookupStage->getSubPipeline_forTest(DOC("_id" << 0));
ASSERT(subPipeline);