diff options
Diffstat (limited to 'src/mongo')
11 files changed, 259 insertions, 218 deletions
diff --git a/src/mongo/db/pipeline/document_source.h b/src/mongo/db/pipeline/document_source.h index f87a81c9be1..56fbaf042bc 100644 --- a/src/mongo/db/pipeline/document_source.h +++ b/src/mongo/db/pipeline/document_source.h @@ -1037,8 +1037,8 @@ private: */ class DocumentSourceMock : public DocumentSource { public: - DocumentSourceMock(std::deque<Document> docs); - DocumentSourceMock(std::deque<Document> docs, + DocumentSourceMock(std::deque<GetNextResult> results); + DocumentSourceMock(std::deque<GetNextResult> results, const boost::intrusive_ptr<ExpressionContext>& expCtx); GetNextResult getNext() override; @@ -1054,8 +1054,10 @@ public: static boost::intrusive_ptr<DocumentSourceMock> create(); - static boost::intrusive_ptr<DocumentSourceMock> create(const Document& doc); - static boost::intrusive_ptr<DocumentSourceMock> create(std::deque<Document> documents); + static boost::intrusive_ptr<DocumentSourceMock> create(Document doc); + + static boost::intrusive_ptr<DocumentSourceMock> create(const GetNextResult& result); + static boost::intrusive_ptr<DocumentSourceMock> create(std::deque<GetNextResult> results); static boost::intrusive_ptr<DocumentSourceMock> create(const char* json); static boost::intrusive_ptr<DocumentSourceMock> create( @@ -1079,7 +1081,7 @@ public: } // Return documents from front of queue. - std::deque<Document> queue; + std::deque<GetNextResult> queue; bool isDisposed = false; bool isDetachedFromOpCtx = false; diff --git a/src/mongo/db/pipeline/document_source_add_fields_test.cpp b/src/mongo/db/pipeline/document_source_add_fields_test.cpp index 63896f31e27..eabea7ff045 100644 --- a/src/mongo/db/pipeline/document_source_add_fields_test.cpp +++ b/src/mongo/db/pipeline/document_source_add_fields_test.cpp @@ -55,8 +55,7 @@ using AddFieldsTest = AggregationContextFixture; TEST_F(AddFieldsTest, ShouldKeepUnspecifiedFieldsReplaceExistingFieldsAndAddNewFields) { auto addFields = DocumentSourceAddFields::create(BSON("e" << 2 << "b" << BSON("c" << 3)), getExpCtx()); - auto mock = - DocumentSourceMock::create({Document{{"a", 1}, {"b", Document{{"c", 1}}}, {"d", 1}}}); + auto mock = DocumentSourceMock::create(Document{{"a", 1}, {"b", Document{{"c", 1}}}, {"d", 1}}); addFields->setSource(mock.get()); auto next = addFields->getNext(); diff --git a/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp b/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp index 1950c23f0d9..17e0c1d7a3b 100644 --- a/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp +++ b/src/mongo/db/pipeline/document_source_bucket_auto_test.cpp @@ -30,6 +30,8 @@ #include <boost/intrusive_ptr.hpp> #include <deque> +#include <string> +#include <utility> #include <vector> #include "mongo/bson/bsonobj.h" @@ -45,8 +47,9 @@ namespace mongo { namespace { -using std::vector; using std::deque; +using std::vector; +using std::string; using boost::intrusive_ptr; class BucketAutoTests : public AggregationContextFixture { @@ -55,11 +58,17 @@ public: return DocumentSourceBucketAuto::createFromBson(bucketAutoSpec.firstElement(), getExpCtx()); } - vector<Document> getResults(BSONObj bucketAutoSpec, deque<Document> docs) { + vector<Document> getResults(BSONObj bucketAutoSpec, deque<Document> inputs) { auto bucketAutoStage = createBucketAuto(bucketAutoSpec); assertBucketAutoType(bucketAutoStage); - auto source = DocumentSourceMock::create(docs); + // Convert Documents to GetNextResults. + deque<DocumentSource::GetNextResult> mockInputs; + for (auto&& input : inputs) { + mockInputs.emplace_back(std::move(input)); + } + + auto source = DocumentSourceMock::create(std::move(mockInputs)); bucketAutoStage->setSource(source.get()); vector<Document> results; @@ -103,15 +112,16 @@ TEST_F(BucketAutoTests, Returns1Of1RequestedBucketWhenAllUniqueValues) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets: 1}}"); // Values are 1, 2, 3, 4 - auto intDocs = {Document{{"x", 4}}, Document{{"x", 1}}, Document{{"x", 3}}, Document{{"x", 2}}}; - auto results = getResults(bucketAutoSpec, intDocs); + auto results = getResults( + bucketAutoSpec, + {Document{{"x", 4}}, Document{{"x", 1}}, Document{{"x", 3}}, Document{{"x", 2}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 1, max : 4}, count : 4}"))); // Values are 'a', 'b', 'c', 'd' - auto stringDocs = { - Document{{"x", "d"}}, Document{{"x", "b"}}, Document{{"x", "a"}}, Document{{"x", "c"}}}; - results = getResults(bucketAutoSpec, stringDocs); + results = getResults( + bucketAutoSpec, + {Document{{"x", "d"}}, Document{{"x", "b"}}, Document{{"x", "a"}}, Document{{"x", "c"}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 'a', max : 'd'}, count : 4}"))); } @@ -120,25 +130,23 @@ TEST_F(BucketAutoTests, Returns1Of1RequestedBucketWithNonUniqueValues) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets: 1}}"); // Values are 1, 2, 7, 7, 7 - auto docs = {Document{{"x", 7}}, - Document{{"x", 1}}, - Document{{"x", 7}}, - Document{{"x", 2}}, - Document{{"x", 7}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 7}}, + Document{{"x", 1}}, + Document{{"x", 7}}, + Document{{"x", 2}}, + Document{{"x", 7}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 1, max : 7}, count : 5}"))); } TEST_F(BucketAutoTests, Returns1Of1RequestedBucketWhen1ValueInSource) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets: 1}}"); - auto intDocs = {Document{{"x", 1}}}; - auto results = getResults(bucketAutoSpec, intDocs); + auto results = getResults(bucketAutoSpec, {Document{{"x", 1}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 1, max : 1}, count : 1}"))); - auto stringDocs = {Document{{"x", "a"}}}; - results = getResults(bucketAutoSpec, stringDocs); + results = getResults(bucketAutoSpec, {Document{{"x", "a"}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 'a', max : 'a'}, count : 1}"))); } @@ -147,12 +155,12 @@ TEST_F(BucketAutoTests, Returns2Of2RequestedBucketsWhenSmallestValueHasManyDupli auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2}}"); // Values are 1, 1, 1, 1, 2 - auto docs = {Document{{"x", 1}}, - Document{{"x", 1}}, - Document{{"x", 1}}, - Document{{"x", 2}}, - Document{{"x", 1}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 1}}, + Document{{"x", 1}}, + Document{{"x", 1}}, + Document{{"x", 2}}, + Document{{"x", 1}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 1, max : 2}, count : 4}"))); ASSERT_DOCUMENT_EQ(results[1], Document(fromjson("{_id : {min : 2, max : 2}, count : 1}"))); @@ -162,16 +170,16 @@ TEST_F(BucketAutoTests, Returns2Of2RequestedBucketsWhenLargestValueHasManyDuplic auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2}}"); // Values are 0, 1, 2, 3, 4, 5, 5, 5, 5 - auto docs = {Document{{"x", 5}}, - Document{{"x", 0}}, - Document{{"x", 2}}, - Document{{"x", 3}}, - Document{{"x", 5}}, - Document{{"x", 1}}, - Document{{"x", 5}}, - Document{{"x", 4}}, - Document{{"x", 5}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 5}}, + Document{{"x", 0}}, + Document{{"x", 2}}, + Document{{"x", 3}}, + Document{{"x", 5}}, + Document{{"x", 1}}, + Document{{"x", 5}}, + Document{{"x", 4}}, + Document{{"x", 5}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 5}, count : 5}"))); @@ -182,15 +190,15 @@ TEST_F(BucketAutoTests, Returns3Of3RequestedBucketsWhenAllUniqueValues) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 3}}"); // Values are 0, 1, 2, 3, 4, 5, 6, 7 - auto docs = {Document{{"x", 2}}, - Document{{"x", 4}}, - Document{{"x", 1}}, - Document{{"x", 7}}, - Document{{"x", 0}}, - Document{{"x", 5}}, - Document{{"x", 3}}, - Document{{"x", 6}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 2}}, + Document{{"x", 4}}, + Document{{"x", 1}}, + Document{{"x", 7}}, + Document{{"x", 0}}, + Document{{"x", 5}}, + Document{{"x", 3}}, + Document{{"x", 6}}}); ASSERT_EQUALS(results.size(), 3UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 3}, count : 3}"))); @@ -205,14 +213,14 @@ TEST_F(BucketAutoTests, Returns2Of3RequestedBucketsWhenLargestValueHasManyDuplic auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 3}}"); // Values are 0, 1, 2, 2, 2, 2, 2 - auto docs = {Document{{"x", 2}}, - Document{{"x", 0}}, - Document{{"x", 2}}, - Document{{"x", 2}}, - Document{{"x", 1}}, - Document{{"x", 2}}, - Document{{"x", 2}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 2}}, + Document{{"x", 0}}, + Document{{"x", 2}}, + Document{{"x", 2}}, + Document{{"x", 1}}, + Document{{"x", 2}}, + Document{{"x", 2}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 2}, count : 2}"))); @@ -227,15 +235,15 @@ TEST_F(BucketAutoTests, Returns1Of3RequestedBucketsWhenLargestValueHasManyDuplic auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 3}}"); // Values are 0, 1, 2, 2, 2, 2, 2, 2 - auto docs = {Document{{"x", 2}}, - Document{{"x", 2}}, - Document{{"x", 0}}, - Document{{"x", 2}}, - Document{{"x", 2}}, - Document{{"x", 2}}, - Document{{"x", 1}}, - Document{{"x", 2}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 2}}, + Document{{"x", 2}}, + Document{{"x", 0}}, + Document{{"x", 2}}, + Document{{"x", 2}}, + Document{{"x", 2}}, + Document{{"x", 1}}, + Document{{"x", 2}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 2}, count : 8}"))); @@ -243,8 +251,8 @@ TEST_F(BucketAutoTests, Returns1Of3RequestedBucketsWhenLargestValueHasManyDuplic TEST_F(BucketAutoTests, Returns3Of3RequestedBucketsWhen3ValuesInSource) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 3}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = + getResults(bucketAutoSpec, {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}}); ASSERT_EQUALS(results.size(), 3UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 1}, count : 1}"))); @@ -254,8 +262,8 @@ TEST_F(BucketAutoTests, Returns3Of3RequestedBucketsWhen3ValuesInSource) { TEST_F(BucketAutoTests, Returns3Of10RequestedBucketsWhen3ValuesInSource) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 10}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = + getResults(bucketAutoSpec, {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}}); ASSERT_EQUALS(results.size(), 3UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 1}, count : 1}"))); @@ -266,8 +274,9 @@ TEST_F(BucketAutoTests, Returns3Of10RequestedBucketsWhen3ValuesInSource) { TEST_F(BucketAutoTests, EvaluatesAccumulatorsInOutputField) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, output : {avg : {$avg : '$x'}}}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", 2}}, Document{{"x", 4}}, Document{{"x", 6}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults( + bucketAutoSpec, + {Document{{"x", 0}}, Document{{"x", 2}}, Document{{"x", 4}}, Document{{"x", 6}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 4}, avg : 1}"))); @@ -276,8 +285,9 @@ TEST_F(BucketAutoTests, EvaluatesAccumulatorsInOutputField) { TEST_F(BucketAutoTests, EvaluatesNonFieldPathExpressionInGroupByField) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : {$add : ['$x', 1]}, buckets : 2}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}, Document{{"x", 3}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults( + bucketAutoSpec, + {Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 2}}, Document{{"x", 3}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 1, max : 3}, count : 2}"))); @@ -286,12 +296,12 @@ TEST_F(BucketAutoTests, EvaluatesNonFieldPathExpressionInGroupByField) { TEST_F(BucketAutoTests, RespectsCanonicalTypeOrderingOfValues) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2}}"); - auto docs = {Document{{"x", "a"}}, - Document{{"x", 1}}, - Document{{"x", "b"}}, - Document{{"x", 2}}, - Document{{"x", 0.0}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", "a"}}, + Document{{"x", 1}}, + Document{{"x", "b"}}, + Document{{"x", 2}}, + Document{{"x", 0.0}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0.0, max : 'a'}, count : 3}"))); @@ -300,7 +310,7 @@ TEST_F(BucketAutoTests, RespectsCanonicalTypeOrderingOfValues) { TEST_F(BucketAutoTests, SourceNameIsBucketAuto) { auto bucketAuto = createBucketAuto(fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2}}")); - ASSERT_EQUALS(std::string(bucketAuto->getSourceName()), "$bucketAuto"); + ASSERT_EQUALS(string(bucketAuto->getSourceName()), "$bucketAuto"); } TEST_F(BucketAutoTests, ShouldAddDependenciesOfGroupByFieldAndComputedFields) { @@ -399,8 +409,7 @@ TEST_F(BucketAutoTests, ShouldBeAbleToReParseSerializedStage) { } TEST_F(BucketAutoTests, ReturnsNoBucketsWhenNoBucketsAreSpecifiedInCreate) { - auto docs = {Document{{"x", 1}}}; - auto mock = DocumentSourceMock::create(docs); + auto mock = DocumentSourceMock::create(Document{{"x", 1}}); auto bucketAuto = DocumentSourceBucketAuto::create(getExpCtx()); bucketAuto->setSource(mock.get()); @@ -501,12 +510,12 @@ TEST_F(BucketAutoTests, FailsWithInvalidOutputFieldName) { } TEST_F(BucketAutoTests, FailsWhenBufferingTooManyDocuments) { - std::deque<Document> inputs; - auto largeStr = std::string(1000, 'b'); + deque<DocumentSource::GetNextResult> inputs; + auto largeStr = string(1000, 'b'); auto inputDoc = Document{{"a", largeStr}}; ASSERT_GTE(inputDoc.getApproximateSize(), 1000UL); - inputs.push_back(inputDoc); - inputs.push_back(Document{{"a", largeStr}}); + inputs.emplace_back(std::move(inputDoc)); + inputs.emplace_back(Document{{"a", largeStr}}); auto mock = DocumentSourceMock::create(inputs); const uint64_t maxMemoryUsageBytes = 1000; @@ -522,12 +531,12 @@ TEST_F(BucketAutoTests, ShouldRoundUpMaximumBoundariesWithGranularitySpecified) fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); // Values are 0, 15, 24, 30, 50 - auto docs = {Document{{"x", 24}}, - Document{{"x", 15}}, - Document{{"x", 30}}, - Document{{"x", 50}}, - Document{{"x", 0}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 24}}, + Document{{"x", 15}}, + Document{{"x", 30}}, + Document{{"x", 50}}, + Document{{"x", 0}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 25}, count : 3}"))); @@ -539,12 +548,12 @@ TEST_F(BucketAutoTests, ShouldRoundDownFirstMinimumBoundaryWithGranularitySpecif fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); // Values are 1, 15, 24, 30, 50 - auto docs = {Document{{"x", 24}}, - Document{{"x", 15}}, - Document{{"x", 30}}, - Document{{"x", 50}}, - Document{{"x", 1}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 24}}, + Document{{"x", 15}}, + Document{{"x", 30}}, + Document{{"x", 50}}, + Document{{"x", 1}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0.63, max : 25}, count : 3}"))); @@ -555,12 +564,12 @@ TEST_F(BucketAutoTests, ShouldAbsorbAllValuesSmallerThanAdjustedBoundaryWithGran auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = {Document{{"x", 0}}, - Document{{"x", 5}}, - Document{{"x", 10}}, - Document{{"x", 15}}, - Document{{"x", 30}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 0}}, + Document{{"x", 5}}, + Document{{"x", 10}}, + Document{{"x", 15}}, + Document{{"x", 30}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 16}, count : 4}"))); @@ -571,12 +580,12 @@ TEST_F(BucketAutoTests, ShouldBeAbleToAbsorbAllValuesIntoOneBucketWithGranularit auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = {Document{{"x", 0}}, - Document{{"x", 5}}, - Document{{"x", 10}}, - Document{{"x", 14}}, - Document{{"x", 15}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults(bucketAutoSpec, + {Document{{"x", 0}}, + Document{{"x", 5}}, + Document{{"x", 10}}, + Document{{"x", 14}}, + Document{{"x", 15}}}); ASSERT_EQUALS(results.size(), 1UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 16}, count : 5}"))); @@ -586,8 +595,9 @@ TEST_F(BucketAutoTests, ShouldNotRoundZeroInFirstBucketWithGranularitySpecified) auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 1}}}; - auto results = getResults(bucketAutoSpec, docs); + auto results = getResults( + bucketAutoSpec, + {Document{{"x", 0}}, Document{{"x", 0}}, Document{{"x", 1}}, Document{{"x", 1}}}); ASSERT_EQUALS(results.size(), 2UL); ASSERT_DOCUMENT_EQ(results[0], Document(fromjson("{_id : {min : 0, max : 0.63}, count : 2}"))); @@ -599,28 +609,37 @@ TEST_F(BucketAutoTests, ShouldFailOnNaNWhenGranularitySpecified) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = {Document{{"x", 0}}, - Document{{"x", std::nan("NaN")}}, - Document{{"x", 1}}, - Document{{"x", 1}}}; - ASSERT_THROWS_CODE(getResults(bucketAutoSpec, docs), UserException, 40259); + ASSERT_THROWS_CODE(getResults(bucketAutoSpec, + {Document{{"x", 0}}, + Document{{"x", std::nan("NaN")}}, + Document{{"x", 1}}, + Document{{"x", 1}}}), + UserException, + 40259); } TEST_F(BucketAutoTests, ShouldFailOnNonNumericValuesWhenGranularitySpecified) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = { - Document{{"x", 0}}, Document{{"x", "test"}}, Document{{"x", 1}}, Document{{"x", 1}}}; - ASSERT_THROWS_CODE(getResults(bucketAutoSpec, docs), UserException, 40258); + ASSERT_THROWS_CODE( + getResults( + bucketAutoSpec, + {Document{{"x", 0}}, Document{{"x", "test"}}, Document{{"x", 1}}, Document{{"x", 1}}}), + UserException, + 40258); } TEST_F(BucketAutoTests, ShouldFailOnNegativeNumbersWhenGranularitySpecified) { auto bucketAutoSpec = fromjson("{$bucketAuto : {groupBy : '$x', buckets : 2, granularity : 'R5'}}"); - auto docs = {Document{{"x", 0}}, Document{{"x", -1}}, Document{{"x", 1}}, Document{{"x", 2}}}; - ASSERT_THROWS_CODE(getResults(bucketAutoSpec, docs), UserException, 40260); + ASSERT_THROWS_CODE( + getResults( + bucketAutoSpec, + {Document{{"x", 0}}, Document{{"x", -1}}, Document{{"x", 1}}, Document{{"x", 2}}}), + UserException, + 40260); } } // namespace } // namespace mongo diff --git a/src/mongo/db/pipeline/document_source_facet_test.cpp b/src/mongo/db/pipeline/document_source_facet_test.cpp index 0f4ee161f75..09424a1aceb 100644 --- a/src/mongo/db/pipeline/document_source_facet_test.cpp +++ b/src/mongo/db/pipeline/document_source_facet_test.cpp @@ -40,9 +40,11 @@ #include "mongo/db/pipeline/aggregation_context_fixture.h" #include "mongo/db/pipeline/document.h" #include "mongo/db/pipeline/document_value_test_util.h" -#include "mongo/util/assert_util.h" +#include "mongo/unittest/unittest.h" namespace mongo { +using std::deque; +using std::vector; // Crutch. bool isMongos() { @@ -193,7 +195,8 @@ TEST_F(DocumentSourceFacetTest, SingleFacetShouldReceiveAllDocuments) { auto facetStage = DocumentSourceFacet::create({{"results", pipeline}}, ctx); - deque<Document> inputs = {Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; + deque<DocumentSource::GetNextResult> inputs = { + Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); @@ -220,14 +223,18 @@ TEST_F(DocumentSourceFacetTest, MultipleFacetsShouldSeeTheSameDocuments) { auto facetStage = DocumentSourceFacet::create({{"first", firstPipeline}, {"second", secondPipeline}}, ctx); - deque<Document> inputs = {Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; + deque<DocumentSource::GetNextResult> inputs = { + Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); auto output = facetStage->getNext(); // The output fields are in no guaranteed order. - vector<Value> expectedOutputs(inputs.begin(), inputs.end()); + vector<Value> expectedOutputs; + for (auto&& input : inputs) { + expectedOutputs.emplace_back(input.releaseDocument()); + } ASSERT(output.isAdvanced()); ASSERT_EQ(output.getDocument().size(), 2UL); ASSERT_VALUE_EQ(output.getDocument()["first"], Value(expectedOutputs)); @@ -252,19 +259,23 @@ TEST_F(DocumentSourceFacetTest, auto facetStage = DocumentSourceFacet::create({{"all", passthroughPipe}, {"first", limitedPipe}}, ctx); - deque<Document> inputs = { + deque<DocumentSource::GetNextResult> inputs = { Document{{"_id", 0}}, Document{{"_id", 1}}, Document{{"_id", 2}}, Document{{"_id", 3}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); + vector<Value> expectedPassthroughOutput; + for (auto&& input : inputs) { + expectedPassthroughOutput.emplace_back(input.getDocument()); + } auto output = facetStage->getNext(); // The output fields are in no guaranteed order. ASSERT(output.isAdvanced()); ASSERT_EQ(output.getDocument().size(), 2UL); - vector<Value> expectedPassthroughOutput(inputs.begin(), inputs.end()); ASSERT_VALUE_EQ(output.getDocument()["all"], Value(expectedPassthroughOutput)); - ASSERT_VALUE_EQ(output.getDocument()["first"], Value(vector<Value>{Value(inputs.front())})); + ASSERT_VALUE_EQ(output.getDocument()["first"], + Value(vector<Value>{Value(expectedPassthroughOutput.front())})); // Should be exhausted now. ASSERT(facetStage->getNext().isEOF()); @@ -281,7 +292,7 @@ TEST_F(DocumentSourceFacetTest, ShouldBeAbleToEvaluateMultipleStagesWithinOneSub auto facetStage = DocumentSourceFacet::create({{"subPipe", pipeline}}, ctx); - deque<Document> inputs = {Document{{"_id", 0}}, Document{{"_id", 1}}}; + deque<DocumentSource::GetNextResult> inputs = {Document{{"_id", 0}}, Document{{"_id", 1}}}; auto mock = DocumentSourceMock::create(inputs); facetStage->setSource(mock.get()); diff --git a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp index 788b02e2825..398831cc728 100644 --- a/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp +++ b/src/mongo/db/pipeline/document_source_graph_lookup_test.cpp @@ -62,7 +62,8 @@ using DocumentSourceGraphLookUpTest = AggregationContextFixture; */ class MockMongodImplementation final : public DocumentSourceNeedsMongod::MongodInterface { public: - MockMongodImplementation(std::deque<Document> documents) : _documents(documents) {} + MockMongodImplementation(std::deque<DocumentSource::GetNextResult> results) + : _results(std::move(results)) {} void setOperationContext(OperationContext* opCtx) final { MONGO_UNREACHABLE; @@ -117,7 +118,7 @@ public: return pipeline.getStatus(); } - pipeline.getValue()->addInitialSource(DocumentSourceMock::create(_documents)); + pipeline.getValue()->addInitialSource(DocumentSourceMock::create(_results)); pipeline.getValue()->injectExpressionContext(expCtx); pipeline.getValue()->optimizePipeline(); @@ -125,17 +126,17 @@ public: } private: - std::deque<Document> _documents; + std::deque<DocumentSource::GetNextResult> _results; }; TEST_F(DocumentSourceGraphLookUpTest, ShouldErrorWhenDoingInitialMatchIfDocumentInFromCollectionIsMissingId) { auto expCtx = getExpCtx(); - std::deque<Document> inputs{Document{{"_id", 0}}}; + std::deque<DocumentSource::GetNextResult> inputs{Document{{"_id", 0}}}; auto inputMock = DocumentSourceMock::create(std::move(inputs)); - std::deque<Document> fromContents{Document{{"to", 0}}}; + std::deque<DocumentSource::GetNextResult> fromContents{Document{{"to", 0}}}; NamespaceString fromNs("test", "graph_lookup"); expCtx->resolvedNamespaces[fromNs.coll()] = {fromNs, std::vector<BSONObj>{}}; @@ -159,11 +160,11 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldErrorWhenExploringGraphIfDocumentInFromCollectionIsMissingId) { auto expCtx = getExpCtx(); - std::deque<Document> inputs{Document{{"_id", 0}}}; + std::deque<DocumentSource::GetNextResult> inputs{Document{{"_id", 0}}}; auto inputMock = DocumentSourceMock::create(std::move(inputs)); - std::deque<Document> fromContents{Document{{"_id", "a"}, {"to", 0}, {"from", 1}}, - Document{{"to", 1}}}; + std::deque<DocumentSource::GetNextResult> fromContents{ + Document{{"_id", "a"}, {"to", 0}, {"from", 1}}, Document{{"to", 1}}}; NamespaceString fromNs("test", "graph_lookup"); expCtx->resolvedNamespaces[fromNs.coll()] = {fromNs, std::vector<BSONObj>{}}; @@ -187,10 +188,10 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldErrorWhenHandlingUnwindIfDocumentInFromCollectionIsMissingId) { auto expCtx = getExpCtx(); - std::deque<Document> inputs{Document{{"_id", 0}}}; + std::deque<DocumentSource::GetNextResult> inputs{Document{{"_id", 0}}}; auto inputMock = DocumentSourceMock::create(std::move(inputs)); - std::deque<Document> fromContents{Document{{"to", 0}}}; + std::deque<DocumentSource::GetNextResult> fromContents{Document{{"to", 0}}}; NamespaceString fromNs("test", "graph_lookup"); expCtx->resolvedNamespaces[fromNs.coll()] = {fromNs, std::vector<BSONObj>{}}; @@ -227,14 +228,15 @@ TEST_F(DocumentSourceGraphLookUpTest, ShouldTraverseSubgraphIfIdOfDocumentsInFromCollectionAreNonUnique) { auto expCtx = getExpCtx(); - std::deque<Document> inputs{Document{{"_id", 0}}}; + std::deque<DocumentSource::GetNextResult> inputs{Document{{"_id", 0}}}; auto inputMock = DocumentSourceMock::create(std::move(inputs)); Document to0from1{{"_id", "a"}, {"to", 0}, {"from", 1}}; Document to0from2{{"_id", "a"}, {"to", 0}, {"from", 2}}; Document to1{{"_id", "b"}, {"to", 1}}; Document to2{{"_id", "c"}, {"to", 2}}; - std::deque<Document> fromContents{to1, to2, to0from1, to0from2}; + std::deque<DocumentSource::GetNextResult> fromContents{ + Document(to1), Document(to2), Document(to0from1), Document(to0from2)}; NamespaceString fromNs("test", "graph_lookup"); expCtx->resolvedNamespaces[fromNs.coll()] = {fromNs, std::vector<BSONObj>{}}; diff --git a/src/mongo/db/pipeline/document_source_group_test.cpp b/src/mongo/db/pipeline/document_source_group_test.cpp index e86be1e96a8..850fc9589d1 100644 --- a/src/mongo/db/pipeline/document_source_group_test.cpp +++ b/src/mongo/db/pipeline/document_source_group_test.cpp @@ -29,6 +29,7 @@ #include "mongo/platform/basic.h" #include <boost/intrusive_ptr.hpp> +#include <deque> #include <map> #include <string> #include <vector> @@ -53,6 +54,7 @@ namespace mongo { namespace { using boost::intrusive_ptr; +using std::deque; using std::map; using std::string; using std::vector; @@ -391,7 +393,7 @@ public: } protected: - virtual std::deque<Document> inputData() { + virtual deque<DocumentSource::GetNextResult> inputData() { return {}; } virtual BSONObj groupSpec() { @@ -444,7 +446,7 @@ class EmptyCollection : public CheckResultsBase {}; /** A $group performed on a single document. */ class SingleDocument : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("a" << 1)}; } virtual BSONObj groupSpec() { @@ -458,7 +460,7 @@ class SingleDocument : public CheckResultsBase { /** A $group performed on two values for a single key. */ class TwoValuesSingleKey : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("a" << 1), DOC("a" << 2)}; } virtual BSONObj groupSpec() { @@ -472,7 +474,7 @@ class TwoValuesSingleKey : public CheckResultsBase { /** A $group performed on two values with one key each. */ class TwoValuesTwoKeys : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("_id" << 0 << "a" << 1), DOC("_id" << 1 << "a" << 2)}; } virtual BSONObj groupSpec() { @@ -489,7 +491,7 @@ class TwoValuesTwoKeys : public CheckResultsBase { /** A $group performed on two values with two keys each. */ class FourValuesTwoKeys : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("id" << 0 << "a" << 1), DOC("id" << 1 << "a" << 2), DOC("id" << 0 << "a" << 3), @@ -509,7 +511,7 @@ class FourValuesTwoKeys : public CheckResultsBase { /** A $group performed on two values with two keys each and two accumulator operations. */ class FourValuesTwoKeysTwoAccumulators : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("id" << 0 << "a" << 1), DOC("id" << 1 << "a" << 2), DOC("id" << 0 << "a" << 3), @@ -531,7 +533,7 @@ class FourValuesTwoKeysTwoAccumulators : public CheckResultsBase { /** Null and undefined _id values are grouped together. */ class GroupNullUndefinedIds : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("a" << BSONNULL << "b" << 100), DOC("b" << 10)}; } virtual BSONObj groupSpec() { @@ -548,7 +550,7 @@ class GroupNullUndefinedIds : public CheckResultsBase { /** A complex _id expression. */ class ComplexId : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {DOC("a" << "de" << "b" @@ -579,7 +581,7 @@ class ComplexId : public CheckResultsBase { /** An undefined accumulator value is dropped. */ class UndefinedAccumulatorValue : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {Document()}; } virtual BSONObj groupSpec() { @@ -954,7 +956,7 @@ public: * SERVER-6766 */ class StringConstantIdAndAccumulatorExpressions : public CheckResultsBase { - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {Document()}; } BSONObj groupSpec() { @@ -974,7 +976,7 @@ public: // Run standard base tests. CheckResultsBase::run(); } - std::deque<Document> inputData() { + deque<DocumentSource::GetNextResult> inputData() { return {Document()}; } BSONObj groupSpec() { diff --git a/src/mongo/db/pipeline/document_source_mock.cpp b/src/mongo/db/pipeline/document_source_mock.cpp index 2781bf12f9f..945aae771f7 100644 --- a/src/mongo/db/pipeline/document_source_mock.cpp +++ b/src/mongo/db/pipeline/document_source_mock.cpp @@ -34,16 +34,17 @@ namespace mongo { using boost::intrusive_ptr; +using std::deque; -DocumentSourceMock::DocumentSourceMock(std::deque<Document> docs) - : DocumentSource(NULL), - queue(std::move(docs)), +DocumentSourceMock::DocumentSourceMock(deque<GetNextResult> results) + : DocumentSource(nullptr), + queue(std::move(results)), sorts(SimpleBSONObjComparator::kInstance.makeBSONObjSet()) {} -DocumentSourceMock::DocumentSourceMock(std::deque<Document> docs, +DocumentSourceMock::DocumentSourceMock(deque<GetNextResult> results, const boost::intrusive_ptr<ExpressionContext>& expCtx) : DocumentSource(expCtx), - queue(std::move(docs)), + queue(std::move(results)), sorts(SimpleBSONObjComparator::kInstance.makeBSONObjSet()) {} const char* DocumentSourceMock::getSourceName() const { @@ -51,24 +52,28 @@ const char* DocumentSourceMock::getSourceName() const { } Value DocumentSourceMock::serialize(bool explain) const { - return Value(DOC(getSourceName() << Document())); + return Value(Document{{getSourceName(), Document()}}); } void DocumentSourceMock::dispose() { isDisposed = true; } -intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(std::deque<Document> docs) { - return new DocumentSourceMock(std::move(docs)); +intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(Document doc) { + return new DocumentSourceMock({std::move(doc)}); +} + +intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(deque<GetNextResult> results) { + return new DocumentSourceMock(std::move(results)); } intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create() { - return new DocumentSourceMock(std::deque<Document>()); + return new DocumentSourceMock(deque<GetNextResult>()); } -intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(const Document& doc) { - std::deque<Document> docs = {doc}; - return new DocumentSourceMock(std::move(docs)); +intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(const GetNextResult& result) { + deque<GetNextResult> results = {result}; + return new DocumentSourceMock(std::move(results)); } intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(const char* json) { @@ -77,11 +82,11 @@ intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create(const char* json) { intrusive_ptr<DocumentSourceMock> DocumentSourceMock::create( const std::initializer_list<const char*>& jsons) { - std::deque<Document> docs; + deque<GetNextResult> results; for (auto&& json : jsons) { - docs.push_back(Document(fromjson(json))); + results.emplace_back(Document(fromjson(json))); } - return new DocumentSourceMock(std::move(docs)); + return new DocumentSourceMock(std::move(results)); } DocumentSource::GetNextResult DocumentSourceMock::getNext() { @@ -92,8 +97,8 @@ DocumentSource::GetNextResult DocumentSourceMock::getNext() { return GetNextResult::makeEOF(); } - Document doc = std::move(queue.front()); + auto next = std::move(queue.front()); queue.pop_front(); - return std::move(doc); + return next; } } diff --git a/src/mongo/db/pipeline/document_source_replace_root_test.cpp b/src/mongo/db/pipeline/document_source_replace_root_test.cpp index 0ba1c7ab2b9..8f7797d6890 100644 --- a/src/mongo/db/pipeline/document_source_replace_root_test.cpp +++ b/src/mongo/db/pipeline/document_source_replace_root_test.cpp @@ -68,7 +68,7 @@ TEST_F(ReplaceRootBasics, FieldPathAsNewRootPromotesSubdocument) { auto replaceRoot = createReplaceRoot(BSON("newRoot" << "$a")); Document subdoc = Document{{"b", 1}, {"c", "hello"}, {"d", Document{{"e", 2}}}}; - auto mock = DocumentSourceMock::create({Document{{"a", subdoc}}}); + auto mock = DocumentSourceMock::create(Document{{"a", subdoc}}); replaceRoot->setSource(mock.get()); auto next = replaceRoot->getNext(); @@ -84,7 +84,7 @@ TEST_F(ReplaceRootBasics, DottedFieldPathAsNewRootPromotesSubdocument) { << "$a.b")); // source document: {a: {b: {c: 3}}} Document subdoc = Document{{"c", 3}}; - auto mock = DocumentSourceMock::create({Document{{"a", Document{{"b", subdoc}}}}}); + auto mock = DocumentSourceMock::create(Document{{"a", Document{{"b", subdoc}}}}); replaceRoot->setSource(mock.get()); auto next = replaceRoot->getNext(); @@ -119,7 +119,7 @@ TEST_F(ReplaceRootBasics, FieldPathAsNewRootPromotesSubdocumentInMultipleDocumen // object. TEST_F(ReplaceRootBasics, ExpressionObjectForNewRootReplacesRootWithThatObject) { auto replaceRoot = createReplaceRoot(BSON("newRoot" << BSON("b" << 1))); - auto mock = DocumentSourceMock::create({Document{{"a", 2}}}); + auto mock = DocumentSourceMock::create(Document{{"a", 2}}); replaceRoot->setSource(mock.get()); auto next = replaceRoot->getNext(); @@ -129,7 +129,7 @@ TEST_F(ReplaceRootBasics, ExpressionObjectForNewRootReplacesRootWithThatObject) BSONObj newObject = BSON("a" << 1 << "b" << 2 << "arr" << BSON_ARRAY(3 << 4 << 5)); replaceRoot = createReplaceRoot(BSON("newRoot" << newObject)); - mock = DocumentSourceMock::create({Document{{"c", 2}}}); + mock = DocumentSourceMock::create(Document{{"c", 2}}); replaceRoot->setSource(mock.get()); next = replaceRoot->getNext(); @@ -138,7 +138,7 @@ TEST_F(ReplaceRootBasics, ExpressionObjectForNewRootReplacesRootWithThatObject) assertExhausted(replaceRoot); replaceRoot = createReplaceRoot(BSON("newRoot" << BSON("a" << BSON("b" << 1)))); - mock = DocumentSourceMock::create({Document{{"c", 2}}}); + mock = DocumentSourceMock::create(Document{{"c", 2}}); replaceRoot->setSource(mock.get()); next = replaceRoot->getNext(); @@ -147,7 +147,7 @@ TEST_F(ReplaceRootBasics, ExpressionObjectForNewRootReplacesRootWithThatObject) assertExhausted(replaceRoot); replaceRoot = createReplaceRoot(BSON("newRoot" << BSON("a" << 2))); - mock = DocumentSourceMock::create({Document{{"b", 2}}}); + mock = DocumentSourceMock::create(Document{{"b", 2}}); replaceRoot->setSource(mock.get()); next = replaceRoot->getNext(); @@ -189,18 +189,18 @@ TEST_F(ReplaceRootBasics, ErrorsWhenNewRootDoesNotEvaluateToAnObject) { << "$a")); // A string is not an object. - auto mock = DocumentSourceMock::create({Document{{"a", "hello"}}}); + auto mock = DocumentSourceMock::create(Document{{"a", "hello"}}); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40228); // An integer is not an object. - mock = DocumentSourceMock::create({Document{{"a", 5}}}); + mock = DocumentSourceMock::create(Document{{"a", 5}}); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40228); // Literals are not objects. replaceRoot = createReplaceRoot(BSON("newRoot" << BSON("$literal" << 1))); - mock = DocumentSourceMock::create({Document()}); + mock = DocumentSourceMock::create(Document()); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40228); assertExhausted(replaceRoot); @@ -208,7 +208,7 @@ TEST_F(ReplaceRootBasics, ErrorsWhenNewRootDoesNotEvaluateToAnObject) { // Most operator expressions do not resolve to objects. replaceRoot = createReplaceRoot(BSON("newRoot" << BSON("$and" << "$a"))); - mock = DocumentSourceMock::create({Document{{"a", true}}}); + mock = DocumentSourceMock::create(Document{{"a", true}}); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40228); assertExhausted(replaceRoot); @@ -220,12 +220,12 @@ TEST_F(ReplaceRootBasics, ErrorsIfNewRootFieldPathDoesNotExist) { auto replaceRoot = createReplaceRoot(BSON("newRoot" << "$a")); - auto mock = DocumentSourceMock::create({Document()}); + auto mock = DocumentSourceMock::create(Document()); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40232); assertExhausted(replaceRoot); - mock = DocumentSourceMock::create({Document{{"e", Document{{"b", Document{{"c", 3}}}}}}}); + mock = DocumentSourceMock::create(Document{{"e", Document{{"b", Document{{"c", 3}}}}}}); replaceRoot->setSource(mock.get()); ASSERT_THROWS_CODE(replaceRoot->getNext(), UserException, 40232); assertExhausted(replaceRoot); diff --git a/src/mongo/db/pipeline/document_source_sort_test.cpp b/src/mongo/db/pipeline/document_source_sort_test.cpp index ae409910fd0..1d54a9a5618 100644 --- a/src/mongo/db/pipeline/document_source_sort_test.cpp +++ b/src/mongo/db/pipeline/document_source_sort_test.cpp @@ -55,6 +55,7 @@ bool isMongos() { namespace { using boost::intrusive_ptr; +using std::deque; using std::string; using std::vector; @@ -184,7 +185,7 @@ TEST_F(DocumentSourceSortTest, OutputSort) { class DocumentSourceSortExecutionTest : public DocumentSourceSortTest { public: - void checkResults(std::deque<Document> inputDocs, + void checkResults(deque<DocumentSource::GetNextResult> inputDocs, BSONObj sortSpec, string expectedResultSetString) { createSort(sortSpec); diff --git a/src/mongo/db/pipeline/document_source_unwind_test.cpp b/src/mongo/db/pipeline/document_source_unwind_test.cpp index 5bb251a64b0..6be7ed5b703 100644 --- a/src/mongo/db/pipeline/document_source_unwind_test.cpp +++ b/src/mongo/db/pipeline/document_source_unwind_test.cpp @@ -104,7 +104,7 @@ protected: return "index"; } - virtual deque<Document> inputData() { + virtual deque<DocumentSource::GetNextResult> inputData() { return {}; } @@ -259,7 +259,7 @@ class Empty : public CheckResultsBase {}; * passed, the document is preserved. */ class EmptyArray : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << BSONArray())}; } string expectedPreservedResultSetString() const override { @@ -275,7 +275,7 @@ class EmptyArray : public CheckResultsBase { * passed, the document is preserved. */ class MissingValue : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0)}; } string expectedPreservedResultSetString() const override { @@ -291,7 +291,7 @@ class MissingValue : public CheckResultsBase { * the document is preserved. */ class Null : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << BSONNULL)}; } string expectedPreservedResultSetString() const override { @@ -307,7 +307,7 @@ class Null : public CheckResultsBase { * passed, the document is preserved. */ class Undefined : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << BSONUndefined)}; } string expectedPreservedResultSetString() const override { @@ -320,7 +320,7 @@ class Undefined : public CheckResultsBase { /** Unwind an array with one value. */ class OneValue : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(1))}; } string expectedResultSetString() const override { @@ -333,7 +333,7 @@ class OneValue : public CheckResultsBase { /** Unwind an array with two values. */ class TwoValues : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(1 << 2))}; } string expectedResultSetString() const override { @@ -346,7 +346,7 @@ class TwoValues : public CheckResultsBase { /** Unwind an array with two values, one of which is null. */ class ArrayWithNull : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(1 << BSONNULL))}; } string expectedResultSetString() const override { @@ -359,7 +359,7 @@ class ArrayWithNull : public CheckResultsBase { /** Unwind two documents with arrays. */ class TwoDocuments : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(1 << 2)), DOC("_id" << 1 << "a" << DOC_ARRAY(3 << 4))}; } @@ -374,7 +374,7 @@ class TwoDocuments : public CheckResultsBase { /** Unwind an array in a nested document. */ class NestedArray : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC("b" << DOC_ARRAY(1 << 2) << "c" << 3))}; } string unwindFieldPath() const override { @@ -394,7 +394,7 @@ class NestedArray : public CheckResultsBase { * preserveNullAndEmptyArrays is specified. */ class NonObjectParent : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << 4)}; } string unwindFieldPath() const override { @@ -410,7 +410,7 @@ class NonObjectParent : public CheckResultsBase { /** Unwind an array in a doubly nested document. */ class DoubleNestedArray : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC("b" << DOC("d" << DOC_ARRAY(1 << 2) << "e" << 4) << "c" << 3))}; } @@ -428,7 +428,7 @@ class DoubleNestedArray : public CheckResultsBase { /** Unwind several documents in a row. */ class SeveralDocuments : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(1 << 2 << 3)), DOC("_id" << 1), DOC("_id" << 2), @@ -469,7 +469,7 @@ class SeveralDocuments : public CheckResultsBase { /** Unwind several more documents in a row. */ class SeveralMoreDocuments : public CheckResultsBase { - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << BSONNULL), DOC("_id" << 1), DOC("_id" << 2 << "a" << DOC_ARRAY("a" @@ -535,7 +535,7 @@ class IncludeArrayIndexSubObject : public CheckResultsBase { string indexPath() const override { return "b.index"; } - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(0) << "b" << DOC("x" << 100)), DOC("_id" << 1 << "a" << 1 << "b" << DOC("x" << 100)), DOC("_id" << 2 << "b" << DOC("x" << 100))}; @@ -563,7 +563,7 @@ class IncludeArrayIndexOverrideExisting : public CheckResultsBase { string indexPath() const override { return "b"; } - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(0) << "b" << 100), DOC("_id" << 1 << "a" << 1 << "b" << 100), DOC("_id" << 2 << "b" << 100)}; @@ -589,7 +589,7 @@ class IncludeArrayIndexOverrideExistingNested : public CheckResultsBase { string indexPath() const override { return "b.index"; } - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(0) << "b" << 100), DOC("_id" << 1 << "a" << 1 << "b" << 100), DOC("_id" << 2 << "b" << 100)}; @@ -618,7 +618,7 @@ class IncludeArrayIndexOverrideUnwindPath : public CheckResultsBase { string indexPath() const override { return "a"; } - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return { DOC("_id" << 0 << "a" << DOC_ARRAY(5)), DOC("_id" << 1 << "a" << 1), DOC("_id" << 2)}; } @@ -644,7 +644,7 @@ class IncludeArrayIndexWithinUnwindPath : public CheckResultsBase { string indexPath() const override { return "a.index"; } - deque<Document> inputData() override { + deque<DocumentSource::GetNextResult> inputData() override { return {DOC("_id" << 0 << "a" << DOC_ARRAY(100 << DOC("b" << 1) << DOC("b" << 1 << "index" << -1)))}; } diff --git a/src/mongo/db/pipeline/tee_buffer_test.cpp b/src/mongo/db/pipeline/tee_buffer_test.cpp index ae6f6b614f3..172a6def935 100644 --- a/src/mongo/db/pipeline/tee_buffer_test.cpp +++ b/src/mongo/db/pipeline/tee_buffer_test.cpp @@ -64,25 +64,25 @@ TEST(TeeBufferTest, ShouldBeExhaustedIfInputIsExhausted) { } TEST(TeeBufferTest, ShouldProvideAllResultsWithoutPauseIfTheyFitInOneBatch) { - std::deque<Document> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; + std::deque<DocumentSource::GetNextResult> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; auto mock = DocumentSourceMock::create(inputDocs); auto teeBuffer = TeeBuffer::create(1); teeBuffer->setSource(mock.get()); auto next = teeBuffer->getNext(0); ASSERT_TRUE(next.isAdvanced()); - ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.front()); + ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.front().getDocument()); next = teeBuffer->getNext(0); ASSERT_TRUE(next.isAdvanced()); - ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.back()); + ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.back().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); } TEST(TeeBufferTest, ShouldProvideAllResultsWithoutPauseIfOnlyOneConsumer) { - std::deque<Document> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; + std::deque<DocumentSource::GetNextResult> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; auto mock = DocumentSourceMock::create(inputDocs); const size_t bufferBytes = 1; // Both docs won't fit in a single batch. @@ -91,18 +91,18 @@ TEST(TeeBufferTest, ShouldProvideAllResultsWithoutPauseIfOnlyOneConsumer) { auto next = teeBuffer->getNext(0); ASSERT_TRUE(next.isAdvanced()); - ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.front()); + ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.front().getDocument()); next = teeBuffer->getNext(0); ASSERT_TRUE(next.isAdvanced()); - ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.back()); + ASSERT_DOCUMENT_EQ(next.getDocument(), inputDocs.back().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); } TEST(TeeBufferTest, ShouldTellConsumerToPauseIfItFinishesBatchBeforeOtherConsumers) { - std::deque<Document> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; + std::deque<DocumentSource::GetNextResult> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; auto mock = DocumentSourceMock::create(inputDocs); const size_t nConsumers = 2; @@ -112,19 +112,19 @@ TEST(TeeBufferTest, ShouldTellConsumerToPauseIfItFinishesBatchBeforeOtherConsume auto next0 = teeBuffer->getNext(0); ASSERT_TRUE(next0.isAdvanced()); - ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.front()); + ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.front().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isPaused()); // Consumer #1 hasn't seen the first doc yet. ASSERT_TRUE(teeBuffer->getNext(0).isPaused()); auto next1 = teeBuffer->getNext(1); ASSERT_TRUE(next1.isAdvanced()); - ASSERT_DOCUMENT_EQ(next1.getDocument(), inputDocs.front()); + ASSERT_DOCUMENT_EQ(next1.getDocument(), inputDocs.front().getDocument()); // Both consumers should be able to advance now. We'll advance consumer #1. next1 = teeBuffer->getNext(1); ASSERT_TRUE(next1.isAdvanced()); - ASSERT_DOCUMENT_EQ(next1.getDocument(), inputDocs.back()); + ASSERT_DOCUMENT_EQ(next1.getDocument(), inputDocs.back().getDocument()); // Consumer #1 should be blocked now. The next input is EOF, but the TeeBuffer didn't get that // far, since the first doc filled up the buffer. @@ -134,7 +134,7 @@ TEST(TeeBufferTest, ShouldTellConsumerToPauseIfItFinishesBatchBeforeOtherConsume // Now exhaust consumer #0. next0 = teeBuffer->getNext(0); ASSERT_TRUE(next0.isAdvanced()); - ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.back()); + ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.back().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); @@ -145,7 +145,7 @@ TEST(TeeBufferTest, ShouldTellConsumerToPauseIfItFinishesBatchBeforeOtherConsume } TEST(TeeBufferTest, ShouldAllowOtherConsumersToAdvanceOnceTrailingConsumerIsDisposed) { - std::deque<Document> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; + std::deque<DocumentSource::GetNextResult> inputDocs{Document{{"a", 1}}, Document{{"a", 2}}}; auto mock = DocumentSourceMock::create(inputDocs); const size_t nConsumers = 2; @@ -155,7 +155,7 @@ TEST(TeeBufferTest, ShouldAllowOtherConsumersToAdvanceOnceTrailingConsumerIsDisp auto next0 = teeBuffer->getNext(0); ASSERT_TRUE(next0.isAdvanced()); - ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.front()); + ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.front().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isPaused()); // Consumer #1 hasn't seen the first doc yet. ASSERT_TRUE(teeBuffer->getNext(0).isPaused()); @@ -166,7 +166,7 @@ TEST(TeeBufferTest, ShouldAllowOtherConsumersToAdvanceOnceTrailingConsumerIsDisp // Consumer #0 should be able to advance now. next0 = teeBuffer->getNext(0); ASSERT_TRUE(next0.isAdvanced()); - ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.back()); + ASSERT_DOCUMENT_EQ(next0.getDocument(), inputDocs.back().getDocument()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); ASSERT_TRUE(teeBuffer->getNext(0).isEOF()); |