summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp')
-rw-r--r--src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp b/src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp
new file mode 100644
index 00000000000..fc95d45e6fa
--- /dev/null
+++ b/src/mongo/db/pipeline/document_source_internal_apply_oplog_update_test.cpp
@@ -0,0 +1,244 @@
+/**
+ * Copyright (C) 2022-present MongoDB, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the Server Side Public License, version 1,
+ * as published by MongoDB, Inc.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * Server Side Public License for more details.
+ *
+ * You should have received a copy of the Server Side Public License
+ * along with this program. If not, see
+ * <http://www.mongodb.com/licensing/server-side-public-license>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the Server Side Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/bson/bsonmisc.h"
+#include "mongo/bson/bsonobj.h"
+#include "mongo/bson/bsonobjbuilder.h"
+#include "mongo/bson/unordered_fields_bsonobj_comparator.h"
+#include "mongo/db/exec/document_value/document.h"
+#include "mongo/db/exec/document_value/document_value_test_util.h"
+#include "mongo/db/exec/document_value/value.h"
+#include "mongo/db/pipeline/aggregation_context_fixture.h"
+#include "mongo/db/pipeline/document_source_internal_apply_oplog_update.h"
+#include "mongo/db/pipeline/document_source_mock.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+using DocumentSourceInternalApplyOplogUpdateTest = AggregationContextFixture;
+
+TEST_F(DocumentSourceInternalApplyOplogUpdateTest, ShouldBeAbleToReParseSerializedStage) {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {oplogUpdate: {"$v": NumberInt(2), diff: {u: {b: 3}}}}})");
+
+ auto stage =
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx());
+
+ std::vector<Value> serialization;
+ stage->serializeToArray(serialization);
+ auto serializedBSON = serialization[0].getDocument().toBson();
+ ASSERT_VALUE_EQ(serialization[0], Value(Document(spec)));
+
+ auto roundTripped = DocumentSourceInternalApplyOplogUpdate::createFromBson(
+ serializedBSON.firstElement(), getExpCtx());
+
+ std::vector<Value> newSerialization;
+ roundTripped->serializeToArray(newSerialization);
+
+ ASSERT_EQ(newSerialization.size(), 1UL);
+ ASSERT_VALUE_EQ(newSerialization[0], serialization[0]);
+}
+
+TEST_F(DocumentSourceInternalApplyOplogUpdateTest, ShouldRejectNonObjectSpecs) {
+ {
+ auto spec = fromjson("{$_internalApplyOplogUpdate: 1}");
+
+ ASSERT_THROWS_CODE(DocumentSourceInternalApplyOplogUpdate::createFromBson(
+ spec.firstElement(), getExpCtx()),
+ DBException,
+ 6315901);
+ }
+
+ {
+ auto spec = fromjson("{$_internalApplyOplogUpdate: []}");
+
+ ASSERT_THROWS_CODE(DocumentSourceInternalApplyOplogUpdate::createFromBson(
+ spec.firstElement(), getExpCtx()),
+ DBException,
+ 6315901);
+ }
+}
+
+TEST_F(DocumentSourceInternalApplyOplogUpdateTest, ShouldRejectMalformedSpecs) {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(999999999), diff: {u: {b: 3}}}
+ }})");
+ ASSERT_THROWS_CODE(
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx()),
+ DBException,
+ 4772600);
+
+ spec = fromjson(R"({$_internalApplyOplogUpdate: {oplogUpdate: {"$v": NumberInt(2)}}})");
+ ASSERT_THROWS_CODE(
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx()),
+ DBException,
+ 4772601);
+
+ spec = fromjson("{$_internalApplyOplogUpdate: {}}");
+ ASSERT_THROWS_CODE(
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx()),
+ DBException,
+ 40414);
+
+ spec =
+ fromjson(R"({$_internalApplyOplogUpdate: {foo: {"$v": NumberInt(2), diff: {u: {b: 3}}}}})");
+ ASSERT_THROWS_CODE(
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx()),
+ DBException,
+ 40415);
+
+ spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {u: {b: 3}}},
+ foo: 1
+ }})");
+ ASSERT_THROWS_CODE(
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx()),
+ DBException,
+ 40415);
+}
+
+TEST_F(DocumentSourceInternalApplyOplogUpdateTest, UpdateMultipleDocuments) {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {sb: {u: {c: 3}}}}
+ }})");
+
+ auto stage =
+ DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(), getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}},
+ Document{{"a", 1}, {"b", 1}},
+ Document{{"a", 2}, {"b", Document{{"c", 1}}}},
+ Document{{"a", 3}, {"b", Document{{"d", 2}}}}},
+ getExpCtx());
+ stage->setSource(mock.get());
+
+ auto next = stage->getNext();
+ ASSERT_TRUE(next.isAdvanced());
+ Document expected = Document{{"a", 0}};
+ ASSERT_DOCUMENT_EQ(next.releaseDocument(), expected);
+
+ next = stage->getNext();
+ ASSERT_TRUE(next.isAdvanced());
+ expected = Document{{"a", 1}, {"b", BSONNULL}};
+ ASSERT_DOCUMENT_EQ(next.releaseDocument(), expected);
+
+ next = stage->getNext();
+ ASSERT_TRUE(next.isAdvanced());
+ expected = Document{{"a", 2}, {"b", Document{{"c", 3}}}};
+ ASSERT_DOCUMENT_EQ(next.releaseDocument(), expected);
+
+ next = stage->getNext();
+ ASSERT_TRUE(next.isAdvanced());
+ expected = Document{{"a", 3}, {"b", Document{{"d", 2}, {"c", 3}}}};
+ ASSERT_DOCUMENT_EQ(next.releaseDocument(), expected);
+
+ ASSERT_TRUE(stage->getNext().isEOF());
+ ASSERT_TRUE(stage->getNext().isEOF());
+ ASSERT_TRUE(stage->getNext().isEOF());
+}
+
+TEST_F(DocumentSourceInternalApplyOplogUpdateTest, ShouldErrorOnInvalidDiffs) {
+ {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {}}
+ }})");
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4770500);
+ }
+
+ {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {q: {z: -7}}}
+ }})");
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4770503);
+ }
+
+ {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {"": {z: -7}}}
+ }})");
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4770505);
+ }
+
+ {
+ auto spec = fromjson(
+ R"({$_internalApplyOplogUpdate: {
+ oplogUpdate: {"$v": NumberInt(2), diff: {sa: []}}
+ }})");
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4770507);
+ }
+
+ {
+ auto spec = BSON("$_internalApplyOplogUpdate"
+ << BSON("oplogUpdate" << BSON("$v" << 2 << "diff"
+ << BSON("u" << BSON("b\0c"_sd << 3)))));
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4728000);
+ }
+
+ {
+ auto spec = BSON(
+ "$_internalApplyOplogUpdate" << BSON(
+ "oplogUpdate" << BSON("$v" << 2 << "diff" << BSON("sb\0c"_sd << BSON("d" << 5)))));
+ auto stage = DocumentSourceInternalApplyOplogUpdate::createFromBson(spec.firstElement(),
+ getExpCtx());
+ auto mock = DocumentSourceMock::createForTest({Document{{"a", 0}}}, getExpCtx());
+ stage->setSource(mock.get());
+ ASSERT_THROWS_CODE(stage->getNext(), DBException, 4770505);
+ }
+}
+
+} // namespace
+} // namespace mongo