summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/document_source_group_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/document_source_group_test.cpp')
-rw-r--r--src/mongo/db/pipeline/document_source_group_test.cpp437
1 files changed, 13 insertions, 424 deletions
diff --git a/src/mongo/db/pipeline/document_source_group_test.cpp b/src/mongo/db/pipeline/document_source_group_test.cpp
index f3bb0863adf..d3ed11f2031 100644
--- a/src/mongo/db/pipeline/document_source_group_test.cpp
+++ b/src/mongo/db/pipeline/document_source_group_test.cpp
@@ -48,7 +48,6 @@
#include "mongo/db/pipeline/dependencies.h"
#include "mongo/db/pipeline/document_source_group.h"
#include "mongo/db/pipeline/document_source_mock.h"
-#include "mongo/db/pipeline/document_source_streaming_group.h"
#include "mongo/db/pipeline/expression.h"
#include "mongo/db/pipeline/expression_context_for_test.h"
#include "mongo/db/query/query_test_service_context.h"
@@ -246,103 +245,6 @@ TEST_F(DocumentSourceGroupTest, ShouldNotReportDottedGroupKeyAsARename) {
ASSERT_EQ(modifiedPathsRet.renames.size(), 0UL);
}
-TEST_F(DocumentSourceGroupTest, GroupRedactsCorrectWithIdNull) {
- auto spec = fromjson(R"({
- $group: {
- _id: null,
- foo: { $count: {} }
- }
- })");
- auto docSource = DocumentSourceGroup::createFromBson(spec.firstElement(), getExpCtx());
- ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({"$group":{"_id":"?null","HASH<foo>":{"$sum":"?number"}}})",
- redact(*docSource));
-}
-
-TEST_F(DocumentSourceGroupTest, GroupRedactsCorrectWithIdSingleField) {
- auto spec = fromjson(R"({
- $group: {
- _id: '$foo'
- }
- })");
- auto docSource = DocumentSourceGroup::createFromBson(spec.firstElement(), getExpCtx());
- ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({
- "$group": {
- "_id": "$HASH<foo>"
- }
- })",
- redact(*docSource));
-}
-
-TEST_F(DocumentSourceGroupTest, GroupRedactsCorrectWithIdDocument) {
- auto spec = fromjson(R"({
- $group: {
- _id: {
- x: '$x',
- y: '$z'
- },
- foo: {
- $sum: {
- $multiply: ['$a.b', '$c', '$d']
- }
- },
- bar: {
- $first: '$baz'
- }
- }
- })");
- auto docSource = DocumentSourceGroup::createFromBson(spec.firstElement(), getExpCtx());
- ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({
- "$group": {
- "_id": {
- "HASH<x>": "$HASH<x>",
- "HASH<y>": "$HASH<z>"
- },
- "HASH<foo>": {
- "$sum": {
- "$multiply": ["$HASH<a>.HASH<b>", "$HASH<c>", "$HASH<d>"]
- }
- },
- "HASH<bar>": {
- "$first": "$HASH<baz>"
- }
- }
- })",
- redact(*docSource));
-}
-
-TEST_F(DocumentSourceGroupTest, StreamingGroupRedactsCorrectly) {
- auto spec = fromjson(R"({
- $_internalStreamingGroup: {
- _id: {
- a: "$a",
- b: "$b"
- },
- a: {
- $first: '$b'
- },
- $monotonicIdFields: [ "a", "b" ]
- }
- })");
- auto docSource = DocumentSourceStreamingGroup::createFromBson(spec.firstElement(), getExpCtx());
- ASSERT_BSONOBJ_EQ_AUTO( // NOLINT
- R"({
- "$_internalStreamingGroup": {
- "_id": {
- "HASH<a>": "$HASH<a>",
- "HASH<b>": "$HASH<b>"
- },
- "HASH<a>": {
- "$first": "$HASH<b>"
- },
- "$monotonicIdFields": [ "HASH<a>", "HASH<b>" ]
- }
- })",
- redact(*docSource));
-}
-
BSONObj toBson(const intrusive_ptr<DocumentSource>& source) {
vector<Value> arr;
source->serializeToArray(arr);
@@ -350,65 +252,32 @@ BSONObj toBson(const intrusive_ptr<DocumentSource>& source) {
return arr[0].getDocument().toBson();
}
-enum class GroupStageType { Default, Streaming };
-
class Base : public ServiceContextTest {
public:
- Base(GroupStageType groupStageType = GroupStageType::Default)
+ Base()
: _opCtx(makeOperationContext()),
_ctx(new ExpressionContextForTest(_opCtx.get(),
AggregateCommandRequest(NamespaceString(ns), {}))),
- _tempDir("DocumentSourceGroupTest"),
- _groupStageType(groupStageType) {}
+ _tempDir("DocumentSourceGroupTest") {}
protected:
- StringData getStageName() const {
- switch (_groupStageType) {
- case GroupStageType::Default:
- return DocumentSourceGroup::kStageName;
- case GroupStageType::Streaming:
- return DocumentSourceStreamingGroup::kStageName;
- default:
- MONGO_UNREACHABLE;
- }
- }
-
- virtual boost::optional<size_t> getMaxMemoryUsageBytes() {
- return boost::none;
- }
-
- intrusive_ptr<DocumentSource> createFromBson(
- BSONElement specElement, intrusive_ptr<ExpressionContext> expressionContext) {
- switch (_groupStageType) {
- case GroupStageType::Default:
- return DocumentSourceGroup::createFromBsonWithMaxMemoryUsage(
- std::move(specElement), expressionContext, getMaxMemoryUsageBytes());
- case GroupStageType::Streaming:
- return DocumentSourceStreamingGroup::createFromBsonWithMaxMemoryUsage(
- std::move(specElement), expressionContext, getMaxMemoryUsageBytes());
- default:
- MONGO_UNREACHABLE;
- }
- }
-
void createGroup(const BSONObj& spec, bool inShard = false, bool inMongos = false) {
- BSONObj namedSpec = BSON(getStageName() << spec);
+ BSONObj namedSpec = BSON("$group" << spec);
BSONElement specElement = namedSpec.firstElement();
intrusive_ptr<ExpressionContextForTest> expressionContext = new ExpressionContextForTest(
_opCtx.get(), AggregateCommandRequest(NamespaceString(ns), {}));
- expressionContext->allowDiskUse = true;
// For $group, 'inShard' implies 'fromMongos' and 'needsMerge'.
expressionContext->fromMongos = expressionContext->needsMerge = inShard;
expressionContext->inMongos = inMongos;
// Won't spill to disk properly if it needs to.
expressionContext->tempDir = _tempDir.path();
- _group = createFromBson(specElement, expressionContext);
+ _group = DocumentSourceGroup::createFromBson(specElement, expressionContext);
assertRoundTrips(_group, expressionContext);
}
- DocumentSourceGroupBase* group() {
- return static_cast<DocumentSourceGroupBase*>(_group.get());
+ DocumentSourceGroup* group() {
+ return static_cast<DocumentSourceGroup*>(_group.get());
}
/** Assert that iterator state accessors consistently report the source is exhausted. */
void assertEOF(const intrusive_ptr<DocumentSource>& source) const {
@@ -430,7 +299,8 @@ private:
// $const operators may be introduced in the first serialization.
BSONObj spec = toBson(group);
BSONElement specElement = spec.firstElement();
- intrusive_ptr<DocumentSource> generated = createFromBson(specElement, expCtx);
+ intrusive_ptr<DocumentSource> generated =
+ DocumentSourceGroup::createFromBson(specElement, expCtx);
ASSERT_BSONOBJ_EQ(spec, toBson(generated));
}
std::unique_ptr<QueryTestServiceContext> _queryServiceContext;
@@ -438,7 +308,6 @@ private:
intrusive_ptr<ExpressionContextForTest> _ctx;
intrusive_ptr<DocumentSource> _group;
TempDir _tempDir;
- GroupStageType _groupStageType;
};
class ParseErrorBase : public Base {
@@ -486,9 +355,10 @@ class IdConstantBase : public ExpressionBase {
class NonObject : public Base {
public:
void _doTest() final {
- BSONObj spec = BSON(getStageName() << "foo");
+ BSONObj spec = BSON("$group"
+ << "foo");
BSONElement specElement = spec.firstElement();
- ASSERT_THROWS(createFromBson(specElement, ctx()), AssertionException);
+ ASSERT_THROWS(DocumentSourceGroup::createFromBson(specElement, ctx()), AssertionException);
}
};
@@ -687,10 +557,8 @@ typedef map<Value, Document, ValueCmp> IdMap;
class CheckResultsBase : public Base {
public:
- CheckResultsBase(GroupStageType groupStageType = GroupStageType::Default)
- : Base(groupStageType) {}
virtual ~CheckResultsBase() {}
- void _doTest() override {
+ void _doTest() {
runSharded(false);
runSharded(true);
}
@@ -703,7 +571,7 @@ public:
if (sharded) {
sink = createMerger();
// Serialize and re-parse the shard stage.
- createGroup(toBson(group())[group()->getSourceName()].Obj(), true);
+ createGroup(toBson(group())["$group"].Obj(), true);
group()->setSource(source.get());
sink->setSource(group());
}
@@ -1003,277 +871,6 @@ public:
}
};
-class StreamingSimple final : public CheckResultsBase {
-public:
- StreamingSimple() : CheckResultsBase(GroupStageType::Streaming) {}
-
-private:
- deque<DocumentSource::GetNextResult> inputData() final {
- return {Document(BSON("a" << 1 << "b" << 1)),
- Document(BSON("a" << 1 << "b" << 2)),
- Document(BSON("a" << 2 << "b" << 3)),
- Document(BSON("a" << 2 << "b" << 1))};
- }
- BSONObj groupSpec() final {
- return BSON("_id"
- << "$a"
- << "sum"
- << BSON("$sum"
- << "$b")
- << "$monotonicIdFields" << BSON_ARRAY("_id"));
- }
- string expectedResultSetString() final {
- return "[{_id:1,sum:3},{_id:2,sum:4}]";
- }
-};
-
-constexpr size_t kBigStringSize = 1024;
-const std::string kBigString(kBigStringSize, 'a');
-
-class CheckResultsAndSpills : public CheckResultsBase {
-public:
- CheckResultsAndSpills(GroupStageType groupStageType, uint64_t expectedSpills)
- : CheckResultsBase(groupStageType), _expectedSpills(expectedSpills) {}
-
- void _doTest() final {
- for (int sharded = 0; sharded < 2; ++sharded) {
- runSharded(sharded);
- const auto* groupStats = static_cast<const GroupStats*>(group()->getSpecificStats());
- ASSERT_EQ(groupStats->spills, _expectedSpills);
- }
- }
-
-private:
- uint64_t _expectedSpills;
-};
-
-template <GroupStageType groupStageType, uint64_t expectedSpills>
-class StreamingSpillTest : public CheckResultsAndSpills {
-public:
- StreamingSpillTest() : CheckResultsAndSpills(groupStageType, expectedSpills) {}
-
-private:
- static constexpr int kCount = 11;
-
- deque<DocumentSource::GetNextResult> inputData() final {
- deque<DocumentSource::GetNextResult> queue;
- for (int i = 0; i < kCount; ++i) {
- queue.emplace_back(Document(BSON("a" << i << "b" << kBigString)));
- }
- return queue;
- }
-
- BSONObj groupSpec() final {
- if constexpr (groupStageType == GroupStageType::Streaming) {
- return fromjson("{_id: '$a', big_array: {$push: '$b'}, $monotonicIdFields: ['_id']}");
- } else {
- return fromjson("{_id: '$a', big_array: {$push: '$b'}}");
- }
- }
-
- boost::optional<size_t> getMaxMemoryUsageBytes() final {
- return 10 * kBigStringSize;
- }
-
- BSONObj expectedResultSet() final {
- BSONArrayBuilder result;
- for (int i = 0; i < kCount; ++i) {
- result << BSON("_id" << i << "big_array" << BSON_ARRAY(kBigString));
- }
- return result.arr();
- }
-};
-
-class WithoutStreamingSpills final
- : public StreamingSpillTest<GroupStageType::Default, 2 /*expectedSpills*/> {};
-class StreamingDoesNotSpill final
- : public StreamingSpillTest<GroupStageType::Streaming, 0 /*expectedSpills*/> {};
-
-class StreamingCanSpill final : public CheckResultsAndSpills {
-public:
- StreamingCanSpill() : CheckResultsAndSpills(GroupStageType::Streaming, 2 /*expectedSpills*/) {}
-
-private:
- static constexpr int kCount = 11;
-
- deque<DocumentSource::GetNextResult> inputData() final {
- deque<DocumentSource::GetNextResult> queue;
- for (int i = 0; i < kCount; ++i) {
- queue.emplace_back(Document(BSON("x" << 0 << "y" << i << "b" << kBigString)));
- }
- return queue;
- }
-
- BSONObj groupSpec() final {
- auto id = BSON("x"
- << "$x"
- << "y"
- << "$y");
- return BSON("_id" << id << "big_array"
- << BSON("$push"
- << "$b")
- << "$monotonicIdFields" << BSON_ARRAY("x"));
- }
-
- boost::optional<size_t> getMaxMemoryUsageBytes() final {
- return 10 * kBigStringSize;
- }
-
- BSONObj expectedResultSet() final {
- BSONArrayBuilder result;
- for (int i = 0; i < kCount; ++i) {
- auto id = BSON("x" << 0 << "y" << i);
- result << BSON("_id" << id << "big_array" << BSON_ARRAY(kBigString));
- }
- return result.arr();
- }
-};
-
-class StreamingAlternatingSpillAndNoSpillBatches : public CheckResultsAndSpills {
-public:
- StreamingAlternatingSpillAndNoSpillBatches()
- : CheckResultsAndSpills(GroupStageType::Streaming, 3 /*expectedSpills*/) {}
-
-private:
- static constexpr int kCount = 12;
-
- deque<DocumentSource::GetNextResult> inputData() final {
- deque<DocumentSource::GetNextResult> queue;
- for (int i = 0; i < kCount; ++i) {
- // For groups with i % 3 == 0 and i % 3 == 1 there should be no spilling, but groups
- // with i % 3 == 2 should spill.
- for (int j = 0; j < (i % 3) + 1; ++j) {
- queue.emplace_back(Document(BSON("a" << i << "b" << kBigString)));
- }
- }
- return queue;
- }
-
- BSONObj groupSpec() final {
- return BSON("_id"
- << "$a"
- << "big_array"
- << BSON("$push"
- << "$b")
- << "$monotonicIdFields" << BSON_ARRAY("_id"));
- }
-
- boost::optional<size_t> getMaxMemoryUsageBytes() final {
- return (25 * kBigStringSize) / 10;
- }
-
- BSONObj expectedResultSet() final {
- BSONArrayBuilder result;
- for (int i = 0; i < kCount; ++i) {
- BSONArrayBuilder bigArrayBuilder;
- for (int j = 0; j < (i % 3) + 1; ++j) {
- bigArrayBuilder << kBigString;
- }
- result << BSON("_id" << i << "big_array" << bigArrayBuilder.arr());
- }
- return result.arr();
- }
-};
-
-class StreamingComplex final : public CheckResultsBase {
-public:
- StreamingComplex() : CheckResultsBase(GroupStageType::Streaming) {}
-
-private:
- static constexpr int kCount = 3;
-
- deque<DocumentSource::GetNextResult> inputData() final {
- deque<DocumentSource::GetNextResult> queue;
- for (int i = 0; i < kCount; ++i) {
- for (int j = 0; j < kCount; ++j) {
- for (int k = 0; k < kCount; ++k) {
- queue.emplace_back(Document(BSON("x" << i << "y" << j << "z" << k)));
- }
- }
- }
- return queue;
- }
-
- BSONObj groupSpec() final {
- BSONObj id = BSON("x"
- << "$x"
- << "y"
- << "$y");
- return BSON("_id" << id << "sum"
- << BSON("$sum"
- << "$z")
- << "$monotonicIdFields" << BSON_ARRAY("x"));
- }
-
- boost::optional<size_t> getMaxMemoryUsageBytes() final {
- return 10 * kBigStringSize;
- }
-
- BSONObj expectedResultSet() final {
- BSONArrayBuilder result;
- for (int i = 0; i < kCount; ++i) {
- for (int j = 0; j < kCount; ++j) {
- result << BSON("_id" << BSON("x" << i << "y" << j) << "sum"
- << (kCount * (kCount - 1)) / 2);
- }
- }
- return result.arr();
- }
-};
-
-class StreamingMultipleMonotonicFields final : public CheckResultsBase {
-public:
- StreamingMultipleMonotonicFields() : CheckResultsBase(GroupStageType::Streaming) {}
-
-private:
- static constexpr int kCount = 6;
- deque<DocumentSource::GetNextResult> inputData() final {
- deque<DocumentSource::GetNextResult> queue;
- generateInputOutput([&queue](int x, int y) {
- for (int i = 0; i < kCount; ++i) {
- queue.emplace_back(Document(BSON("x" << x << "y" << y << "z" << i)));
- }
- });
- return queue;
- }
-
- BSONObj groupSpec() final {
- return fromjson(
- "{_id: {x: '$x', y: '$y'}, sum: {$sum: '$z'}, $monotonicIdFields: ['x', 'y']}");
- }
-
- boost::optional<size_t> getMaxMemoryUsageBytes() final {
- return 10 * kBigStringSize;
- }
-
- BSONObj expectedResultSet() final {
- BSONArrayBuilder result;
- const int sum = (kCount * (kCount - 1)) / 2;
- generateInputOutput([&](int x, int y) {
- result << BSON("_id" << BSON("x" << x << "y" << y) << "sum" << sum);
- });
- return result.arr();
- }
-
- template <typename Callback>
- void generateInputOutput(const Callback& callback) {
- int x = 0;
- int y = 0;
- for (int i = 0; i < kCount; ++i) {
- callback(x, y);
- int state = i % 3;
- if (state == 0) {
- x++;
- } else if (state == 1) {
- y++;
- } else {
- x++;
- y++;
- }
- }
- }
-};
-
class All : public OldStyleSuiteSpecification {
public:
All() : OldStyleSuiteSpecification("DocumentSourceGroupTests") {}
@@ -1314,14 +911,6 @@ public:
add<Dependencies>();
add<StringConstantIdAndAccumulatorExpressions>();
add<ArrayConstantAccumulatorExpression>();
-
- add<StreamingSimple>();
- add<WithoutStreamingSpills>();
- add<StreamingDoesNotSpill>();
- add<StreamingCanSpill>();
- add<StreamingAlternatingSpillAndNoSpillBatches>();
- add<StreamingComplex>();
- add<StreamingMultipleMonotonicFields>();
#if 0
// Disabled tests until SERVER-23318 is implemented.
add<StreamingOptimization>();