summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Dashti <mdashti@gmail.com>2023-02-04 01:50:41 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2023-02-04 02:49:00 +0000
commitea2db11ad2889935f4922905794dc032dafb102a (patch)
treefa314ad7cc25a03d3591a5116096424044ff45db
parentdfd8a86021ae6d588c4f6fd46dab70176f672e0e (diff)
downloadmongo-ea2db11ad2889935f4922905794dc032dafb102a.tar.gz
SERVER-67412 Removed support for parsing '$v:1' oplog entries in change streams
-rw-r--r--src/mongo/db/pipeline/change_stream_event_transform.cpp32
-rw-r--r--src/mongo/db/pipeline/document_source_change_stream_test.cpp110
-rw-r--r--src/mongo/db/update/SConscript1
-rw-r--r--src/mongo/db/update/update_oplog_entry_serialization.cpp48
-rw-r--r--src/mongo/db/update/update_oplog_entry_serialization.h4
-rw-r--r--src/mongo/db/update/update_oplog_entry_serialization_test.cpp115
-rw-r--r--src/mongo/db/update/update_oplog_entry_version.h2
7 files changed, 178 insertions, 134 deletions
diff --git a/src/mongo/db/pipeline/change_stream_event_transform.cpp b/src/mongo/db/pipeline/change_stream_event_transform.cpp
index 62c795caaad..0c17457ebc4 100644
--- a/src/mongo/db/pipeline/change_stream_event_transform.cpp
+++ b/src/mongo/db/pipeline/change_stream_event_transform.cpp
@@ -218,33 +218,11 @@ Document ChangeStreamDefaultEventTransformation::applyTransformation(const Docum
{"disambiguatedPaths",
showDisambiguatedPaths ? Value(deltaDesc.disambiguatedPaths) : Value()}});
}
- } else if (id.missing()) {
- operationType = DocumentSourceChangeStream::kUpdateOpType;
- checkValueType(input[repl::OplogEntry::kObjectFieldName],
- repl::OplogEntry::kObjectFieldName,
- BSONType::Object);
-
- if (_changeStreamSpec.getShowRawUpdateDescription()) {
- updateDescription = input[repl::OplogEntry::kObjectFieldName];
- } else {
- Document opObject = input[repl::OplogEntry::kObjectFieldName].getDocument();
- Value updatedFields = opObject["$set"];
- Value removedFields = opObject["$unset"];
-
- // Extract the field names of $unset document.
- std::vector<Value> removedFieldsVector;
- if (removedFields.getType() == BSONType::Object) {
- auto iter = removedFields.getDocument().fieldIterator();
- while (iter.more()) {
- removedFieldsVector.push_back(Value(iter.next().first));
- }
- }
-
- updateDescription = Value(
- Document{{"updatedFields",
- updatedFields.missing() ? Value(Document()) : updatedFields},
- {"removedFields", removedFieldsVector}});
- }
+ } else if (!oplogVersion.missing() || id.missing()) {
+ // This is not a replacement op, and we did not see a valid update version number.
+ uasserted(6741200,
+ str::stream() << "Unsupported or missing oplog version, $v: "
+ << oplogVersion.toString());
} else {
operationType = DocumentSourceChangeStream::kReplaceOpType;
fullDocument = input[repl::OplogEntry::kObjectFieldName];
diff --git a/src/mongo/db/pipeline/document_source_change_stream_test.cpp b/src/mongo/db/pipeline/document_source_change_stream_test.cpp
index cdbae5ee5d3..1c48b6fbf3e 100644
--- a/src/mongo/db/pipeline/document_source_change_stream_test.cpp
+++ b/src/mongo/db/pipeline/document_source_change_stream_test.cpp
@@ -202,13 +202,21 @@ public:
const BSONObj& spec = kDefaultSpec,
const boost::optional<Document> expectedInvalidate = {},
const std::vector<repl::OplogEntry> transactionEntries = {},
- std::vector<Document> documentsForLookup = {}) {
+ std::vector<Document> documentsForLookup = {},
+ const boost::optional<std::int32_t> expectedErrorCode = {}) {
vector<intrusive_ptr<DocumentSource>> stages = makeStages(entry.getEntry().toBSON(), spec);
auto lastStage = stages.back();
getExpCtx()->mongoProcessInterface =
std::make_unique<MockMongoInterface>(transactionEntries, std::move(documentsForLookup));
+ if (expectedErrorCode) {
+ ASSERT_THROWS_CODE(lastStage->getNext(),
+ AssertionException,
+ ErrorCodes::Error(expectedErrorCode.get()));
+ return;
+ }
+
auto next = lastStage->getNext();
// Match stage should pass the doc down if expectedDoc is given.
ASSERT_EQ(next.isAdvanced(), static_cast<bool>(expectedDoc));
@@ -743,7 +751,8 @@ TEST_F(ChangeStreamStageTest, TransformInsertFromMigrateShowMigrations) {
}
TEST_F(ChangeStreamStageTest, TransformUpdateFields) {
- BSONObj o = BSON("$set" << BSON("y" << 1));
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -752,13 +761,19 @@ TEST_F(ChangeStreamStageTest, TransformUpdateFields) {
boost::none, // fromMigrate
o2); // o2
- const auto expectedUpdateField = makeExpectedUpdateEvent(
- kDefaultTs, nss, o2, D{{"updatedFields", D{{"y", 1}}}, {"removedFields", vector<V>()}});
+ const auto expectedUpdateField = makeExpectedUpdateEvent(kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{{"y", 1}}},
+ {"removedFields", vector<V>()},
+ {"truncatedArrays", vector<V>()}});
+
checkTransformation(updateField, expectedUpdateField);
}
TEST_F(ChangeStreamStageTest, TransformUpdateFieldsShowExpandedEvents) {
- BSONObj o = BSON("$set" << BSON("y" << 1));
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -767,12 +782,14 @@ TEST_F(ChangeStreamStageTest, TransformUpdateFieldsShowExpandedEvents) {
boost::none, // fromMigrate
o2); // o2
- const auto expectedUpdateField =
- makeExpectedUpdateEvent(kDefaultTs,
- nss,
- o2,
- D{{"updatedFields", D{{"y", 1}}}, {"removedFields", vector<V>()}},
- true /* expanded events */);
+ const auto expectedUpdateField = makeExpectedUpdateEvent(kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{{"y", 1}}},
+ {"removedFields", vector<V>()},
+ {"truncatedArrays", vector<V>()},
+ {"disambiguatedPaths", D{}}},
+ true /* expanded events */);
checkTransformation(updateField, expectedUpdateField, kShowExpandedEventsSpec);
}
@@ -905,7 +922,8 @@ TEST_F(ChangeStreamStageTest, TransformDeltaOplogNestedComplexSubDiffs) {
// Legacy documents might not have an _id field; then the document key is the full (post-update)
// document.
TEST_F(ChangeStreamStageTest, TransformUpdateFieldsLegacyNoId) {
- BSONObj o = BSON("$set" << BSON("y" << 1));
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("x" << 1 << "y" << 1);
auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -914,13 +932,18 @@ TEST_F(ChangeStreamStageTest, TransformUpdateFieldsLegacyNoId) {
boost::none, // fromMigrate
o2); // o2
- const auto expectedUpdateField = makeExpectedUpdateEvent(
- kDefaultTs, nss, o2, D{{"updatedFields", D{{"y", 1}}}, {"removedFields", vector<V>()}});
+ const auto expectedUpdateField = makeExpectedUpdateEvent(kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{{"y", 1}}},
+ {"removedFields", vector<V>()},
+ {"truncatedArrays", vector<V>()}});
checkTransformation(updateField, expectedUpdateField);
}
TEST_F(ChangeStreamStageTest, TransformRemoveFields) {
- BSONObj o = BSON("$unset" << BSON("y" << 1));
+ BSONObj diff = BSON("d" << BSON("y" << false));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto removeField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -930,7 +953,10 @@ TEST_F(ChangeStreamStageTest, TransformRemoveFields) {
o2); // o2
const auto expectedUpdateField = makeExpectedUpdateEvent(
- kDefaultTs, nss, o2, D{{"updatedFields", D{}}, {"removedFields", {"y"_sd}}});
+ kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{}}, {"removedFields", {"y"_sd}}, {"truncatedArrays", vector<V>()}});
checkTransformation(removeField, expectedUpdateField);
} // namespace
@@ -2306,7 +2332,6 @@ TEST_F(ChangeStreamStageTest, PreparedTransactionEndingWithEmptyApplyOps) {
TEST_F(ChangeStreamStageTest, TransformApplyOps) {
// Doesn't use the checkTransformation() pattern that other tests use since we expect multiple
// documents to be returned from one applyOps.
-
Document applyOpsDoc{
{"applyOps",
Value{std::vector<Document>{
@@ -2317,7 +2342,10 @@ TEST_F(ChangeStreamStageTest, TransformApplyOps) {
Document{{"op", "u"_sd},
{"ns", nss.ns()},
{"ui", testUuid()},
- {"o", Value{Document{{"$set", Value{Document{{"x", "hallo 2"_sd}}}}}}},
+ {"o",
+ Value{Document{
+ {"diff", Value{Document{{"u", Value{Document{{"x", "hallo 2"_sd}}}}}}},
+ {"$v", 2}}}},
{"o2", Value{Document{{"_id", 123}}}}},
// Operation on another namespace which should be skipped.
Document{{"op", "i"_sd},
@@ -2412,7 +2440,8 @@ TEST_F(ChangeStreamStageTest, ClusterTimeMatchesOplogEntry) {
const auto opTime = repl::OpTime(ts, term);
// Test the 'clusterTime' field is copied from the oplog entry for an update.
- BSONObj o = BSON("$set" << BSON("y" << 1));
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -2422,8 +2451,12 @@ TEST_F(ChangeStreamStageTest, ClusterTimeMatchesOplogEntry) {
o2, // o2
opTime); // opTime
- const auto expectedUpdateField = makeExpectedUpdateEvent(
- ts, nss, o2, D{{"updatedFields", D{{"y", 1}}}, {"removedFields", vector<V>()}});
+ const auto expectedUpdateField = makeExpectedUpdateEvent(ts,
+ nss,
+ o2,
+ D{{"updatedFields", D{{"y", 1}}},
+ {"removedFields", vector<V>()},
+ {"truncatedArrays", vector<V>()}});
checkTransformation(updateField, expectedUpdateField);
// Test the 'clusterTime' field is copied from the oplog entry for a collection drop.
@@ -3070,18 +3103,40 @@ TEST_F(ChangeStreamStageDBTest, TransformsEntriesForLegalClientCollectionsWithSy
}
}
-TEST_F(ChangeStreamStageDBTest, TransformUpdateFields) {
+TEST_F(ChangeStreamStageDBTest, TransformUpdateFieldsVMissingNotSupported) {
+ // A missing $v field in the update oplog entry implies $v:1, which is no longer supported.
BSONObj o = BSON("$set" << BSON("y" << 1));
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, nss, o, testUuid(), boost::none, o2);
+ checkTransformation(updateField, boost::none, kDefaultSpec, {}, {}, {}, 6741200);
+}
- const auto expectedUpdateField = makeExpectedUpdateEvent(
- kDefaultTs, nss, o2, D{{"updatedFields", D{{"y", 1}}}, {"removedFields", vector<V>()}});
+TEST_F(ChangeStreamStageDBTest, TransformUpdateFieldsNonV2NotSupported) {
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 3);
+ BSONObj o2 = BSON("_id" << 1 << "x" << 2);
+ auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, nss, o, testUuid(), boost::none, o2);
+ checkTransformation(updateField, boost::none, kDefaultSpec, {}, {}, {}, 6741200);
+}
+
+TEST_F(ChangeStreamStageDBTest, TransformUpdateFields) {
+ BSONObj diff = BSON("u" << BSON("y" << 1));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
+ BSONObj o2 = BSON("_id" << 1 << "x" << 2);
+ auto updateField = makeOplogEntry(OpTypeEnum::kUpdate, nss, o, testUuid(), boost::none, o2);
+
+ const auto expectedUpdateField = makeExpectedUpdateEvent(kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{{"y", 1}}},
+ {"removedFields", vector<V>()},
+ {"truncatedArrays", vector<V>()}});
checkTransformation(updateField, expectedUpdateField);
}
TEST_F(ChangeStreamStageDBTest, TransformRemoveFields) {
- BSONObj o = BSON("$unset" << BSON("y" << 1));
+ BSONObj diff = BSON("d" << BSON("y" << false));
+ BSONObj o = BSON("diff" << diff << "$v" << 2);
BSONObj o2 = BSON("_id" << 1 << "x" << 2);
auto removeField = makeOplogEntry(OpTypeEnum::kUpdate, // op type
nss, // namespace
@@ -3091,7 +3146,10 @@ TEST_F(ChangeStreamStageDBTest, TransformRemoveFields) {
o2); // o2
const auto expectedRemoveField = makeExpectedUpdateEvent(
- kDefaultTs, nss, o2, D{{"updatedFields", D{}}, {"removedFields", {"y"_sd}}});
+ kDefaultTs,
+ nss,
+ o2,
+ D{{"updatedFields", D{}}, {"removedFields", {"y"_sd}}, {"truncatedArrays", vector<V>()}});
checkTransformation(removeField, expectedRemoveField);
}
diff --git a/src/mongo/db/update/SConscript b/src/mongo/db/update/SConscript
index 798c490d7fd..a571468bc3f 100644
--- a/src/mongo/db/update/SConscript
+++ b/src/mongo/db/update/SConscript
@@ -169,6 +169,7 @@ env.CppUnitTest(
'update_array_node_test.cpp',
'update_driver_test.cpp',
'update_object_node_test.cpp',
+ 'update_oplog_entry_serialization_test.cpp',
'update_serialization_test.cpp',
'v2_log_builder_test.cpp',
],
diff --git a/src/mongo/db/update/update_oplog_entry_serialization.cpp b/src/mongo/db/update/update_oplog_entry_serialization.cpp
index daee76db1c2..55c5d1f2d6e 100644
--- a/src/mongo/db/update/update_oplog_entry_serialization.cpp
+++ b/src/mongo/db/update/update_oplog_entry_serialization.cpp
@@ -29,9 +29,13 @@
#include "mongo/db/update/update_oplog_entry_serialization.h"
+#include <fmt/format.h>
+
#include "mongo/db/update/document_diff_serialization.h"
#include "mongo/db/update/update_oplog_entry_version.h"
+using namespace fmt::literals;
+
namespace mongo::update_oplog_entry {
BSONObj makeDeltaOplogEntry(const doc_diff::Diff& diff) {
BSONObjBuilder builder;
@@ -53,19 +57,6 @@ boost::optional<BSONObj> extractDiffFromOplogEntry(const BSONObj& opLog) {
}
namespace {
-BSONElement extractNewValueForFieldFromV1Entry(const BSONObj& oField, StringData fieldName) {
- // Check the '$set' section.
- auto setElt = oField["$set"];
- if (setElt.ok()) {
- // The $set field in a $v:1 entry should always be an object.
- invariant(setElt.type() == BSONType::Object);
- return setElt.embeddedObject()[fieldName];
- }
-
- // The field is either in the $unset section, or was not modified at all.
- return BSONElement();
-}
-
BSONElement extractNewValueForFieldFromV2Entry(const BSONObj& oField, StringData fieldName) {
auto diffField = oField[kDiffObjectFieldName];
@@ -84,17 +75,6 @@ BSONElement extractNewValueForFieldFromV2Entry(const BSONObj& oField, StringData
return BSONElement();
}
-FieldRemovedStatus isFieldRemovedByV1Update(const BSONObj& oField, StringData fieldName) {
- auto unsetElt = oField["$unset"];
- if (unsetElt.ok()) {
- invariant(unsetElt.type() == BSONType::Object);
- if (unsetElt.embeddedObject()[fieldName].ok()) {
- return FieldRemovedStatus::kFieldRemoved;
- }
- }
- return FieldRemovedStatus::kFieldNotRemoved;
-}
-
FieldRemovedStatus isFieldRemovedByV2Update(const BSONObj& oField, StringData fieldName) {
auto diffField = oField[kDiffObjectFieldName];
@@ -122,20 +102,12 @@ UpdateType extractUpdateType(const BSONObj& updateDocument) {
// to omit the $v field so that case must be handled carefully.
auto vElt = updateDocument[kUpdateOplogEntryVersionFieldName];
- if (!vElt.ok()) {
- // We're dealing with a $v:1 entry if the first field name starts with a '$' and there is no
- // $v field.
- if (updateDocument.firstElementFieldNameStringData().startsWith("$")) {
- return UpdateType::kV1Modifier;
- }
- } else if (vElt.numberInt() == static_cast<int>(UpdateOplogEntryVersion::kUpdateNodeV1)) {
- return UpdateType::kV1Modifier;
- } else if (vElt.numberInt() == static_cast<int>(UpdateOplogEntryVersion::kDeltaV2)) {
+ if (vElt.ok() && vElt.numberInt() == static_cast<int>(UpdateOplogEntryVersion::kDeltaV2)) {
return UpdateType::kV2Delta;
}
// Unrecognized oplog entry version.
- MONGO_UNREACHABLE_TASSERT(6448500);
+ tasserted(6448500, str::stream() << "Unsupported or missing oplog version, " << vElt);
}
BSONElement extractNewValueForField(const BSONObj& oField, StringData fieldName) {
@@ -143,9 +115,7 @@ BSONElement extractNewValueForField(const BSONObj& oField, StringData fieldName)
auto type = extractUpdateType(oField);
- if (type == UpdateType::kV1Modifier) {
- return extractNewValueForFieldFromV1Entry(oField, fieldName);
- } else if (type == UpdateType::kV2Delta) {
+ if (type == UpdateType::kV2Delta) {
return extractNewValueForFieldFromV2Entry(oField, fieldName);
} else if (type == UpdateType::kReplacement) {
return oField[fieldName];
@@ -160,9 +130,7 @@ FieldRemovedStatus isFieldRemovedByUpdate(const BSONObj& oField, StringData fiel
auto type = extractUpdateType(oField);
- if (type == UpdateType::kV1Modifier) {
- return isFieldRemovedByV1Update(oField, fieldName);
- } else if (type == UpdateType::kV2Delta) {
+ if (type == UpdateType::kV2Delta) {
return isFieldRemovedByV2Update(oField, fieldName);
} else if (type == UpdateType::kReplacement) {
// The field was definitely *not* removed if it's still in the post image. Otherwise,
diff --git a/src/mongo/db/update/update_oplog_entry_serialization.h b/src/mongo/db/update/update_oplog_entry_serialization.h
index a438c9ee5e2..018f819071f 100644
--- a/src/mongo/db/update/update_oplog_entry_serialization.h
+++ b/src/mongo/db/update/update_oplog_entry_serialization.h
@@ -33,8 +33,7 @@
#include "mongo/db/update/update_oplog_entry_version.h"
/**
- * This provides helpers for creating oplog entries. To create a $v: 1 modifier-style oplog
- * entry, a LogBuilder must be used instead.
+ * This provides helpers for creating oplog entries.
*/
namespace mongo::update_oplog_entry {
static inline constexpr StringData kDiffObjectFieldName = "diff"_sd;
@@ -51,7 +50,6 @@ constexpr size_t kSizeOfDeltaOplogEntryMetadata = 15;
*/
enum class UpdateType {
kReplacement,
- kV1Modifier,
kV2Delta,
};
diff --git a/src/mongo/db/update/update_oplog_entry_serialization_test.cpp b/src/mongo/db/update/update_oplog_entry_serialization_test.cpp
index 4dd08705f4b..b6ef9b1692e 100644
--- a/src/mongo/db/update/update_oplog_entry_serialization_test.cpp
+++ b/src/mongo/db/update/update_oplog_entry_serialization_test.cpp
@@ -41,45 +41,56 @@
namespace mongo::update_oplog_entry {
namespace {
-TEST(UpdateOplogSerializationTest, ReadV1EntryWithVersionField) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithVersionField,
+ "Tripwire assertion.*6448500") {
auto setField = BSON("a" << 1 << "b" << 2);
BSONObj o(BSON("$v" << 1 << "$set" << setField));
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "a"), setField["a"]);
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "b"), setField["b"]);
-
- ASSERT(isFieldRemovedByUpdate(o, "a") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "z") == FieldRemovedStatus::kFieldNotRemoved);
+ extractNewValueForField(o, "a");
}
-TEST(UpdateOplogSerializationTest, ReadV1EntryWithoutVersionField) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithoutVersionField_NotSupported1,
+ "Tripwire assertion.*6448500") {
auto setField = BSON("a" << 1 << "b" << 2);
BSONObj o(BSON("$set" << setField));
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "a"), setField["a"]);
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "b"), setField["b"]);
+ extractNewValueForField(o, "a");
+}
- ASSERT(isFieldRemovedByUpdate(o, "a") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "z") == FieldRemovedStatus::kFieldNotRemoved);
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithoutVersionField_NotSupported2,
+ "Tripwire assertion.*6448500") {
+ auto setField = BSON("a" << 1 << "b" << 2);
+ BSONObj o(BSON("$set" << setField));
+
+ isFieldRemovedByUpdate(o, "a");
}
-TEST(UpdateOplogSerializationTest, ReadV1EntryWithSetAndUnset) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithSetAndUnset_NotSupported1,
+ "Tripwire assertion.*6448500") {
auto setField = BSON("a" << 1 << "b" << 2);
auto unsetField = BSON("c" << true << "d" << true);
BSONObj o(BSON("$set" << setField << "$unset" << unsetField));
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "a"), setField["a"]);
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "b"), setField["b"]);
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "c"), BSONElement());
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "d"), BSONElement());
+ extractNewValueForField(o, "a");
+}
+
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithSetAndUnset_NotSupported2,
+ "Tripwire assertion.*6448500") {
+ auto setField = BSON("a" << 1 << "b" << 2);
+ auto unsetField = BSON("c" << true << "d" << true);
+ BSONObj o(BSON("$set" << setField << "$unset" << unsetField));
- ASSERT(isFieldRemovedByUpdate(o, "a") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "b") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "c") == FieldRemovedStatus::kFieldRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "d") == FieldRemovedStatus::kFieldRemoved);
+ isFieldRemovedByUpdate(o, "a");
}
-TEST(UpdateOplogSerializationTest, ReadV1EntryWhichIncludesDottedPath) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWhichIncludesDottedPath_NotSupported1,
+ "Tripwire assertion.*6448500") {
// While our function for getting modified fields only supports top-level fields,
// there should be no problem if the oplog entry contains modifications to
// dotted paths.
@@ -88,12 +99,21 @@ TEST(UpdateOplogSerializationTest, ReadV1EntryWhichIncludesDottedPath) {
auto unsetField = BSON("d.e.f" << true << "y" << true);
BSONObj o(BSON("$set" << setField << "$unset" << unsetField));
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "x"), setField["x"]);
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "y"), BSONElement());
+ extractNewValueForField(o, "x");
+}
+
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWhichIncludesDottedPath_NotSupported2,
+ "Tripwire assertion.*6448500") {
+ // While our function for getting modified fields only supports top-level fields,
+ // there should be no problem if the oplog entry contains modifications to
+ // dotted paths.
+
+ auto setField = BSON("a.b.c" << 1 << "x" << 2);
+ auto unsetField = BSON("d.e.f" << true << "y" << true);
+ BSONObj o(BSON("$set" << setField << "$unset" << unsetField));
- ASSERT(isFieldRemovedByUpdate(o, "x") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "y") == FieldRemovedStatus::kFieldRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "z") == FieldRemovedStatus::kFieldNotRemoved);
+ isFieldRemovedByUpdate(o, "x");
}
TEST(UpdateOplogSerializationTest, ReadV2Entry) {
@@ -114,12 +134,22 @@ TEST(UpdateOplogSerializationTest, ReadV2Entry) {
ASSERT(isFieldRemovedByUpdate(o, "nonexistentField") == FieldRemovedStatus::kFieldNotRemoved);
}
-TEST(UpdateOplogSerializationTest, ReadV1EntryWithSubfieldModified) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithSubfieldModified_NotSupported1,
+ "Tripwire assertion.*6448500") {
auto setField = BSON("a.b" << 1 << "x" << 2);
BSONObj o(BSON("$set" << setField));
// We cannot recover the entire new value for field 'a' so an EOO element is returned.
- ASSERT_BSONELT_EQ(extractNewValueForField(o, "a"), BSONElement());
+ extractNewValueForField(o, "a");
+}
+
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadV1EntryWithSubfieldModified_NotSupported2,
+ "Tripwire assertion.*6448500") {
+ auto setField = BSON("a.b" << 1 << "x" << 2);
+ BSONObj o(BSON("$set" << setField));
+
ASSERT(isFieldRemovedByUpdate(o, "a") == FieldRemovedStatus::kFieldNotRemoved);
}
@@ -132,29 +162,40 @@ TEST(UpdateOplogSerializationTest, ReadV2EntryWithSubfieldModified) {
ASSERT(isFieldRemovedByUpdate(o, "a") == FieldRemovedStatus::kFieldNotRemoved);
}
-TEST(UpdateOplogSerializationTest, ReadReplacementEntry) {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadReplacementEntry_NotSupported1,
+ "Tripwire assertion.*6448500") {
BSONObj o(BSON("foo" << 1 << "bar" << 2));
- ASSERT_EQ(extractNewValueForField(o, "foo"), o["foo"]);
- ASSERT_EQ(extractNewValueForField(o, "bar"), o["bar"]);
+ isFieldRemovedByUpdate(o, "bar");
+}
+
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ ReadReplacementEntry_NotSupported2,
+ "Tripwire assertion.*6448500") {
+ BSONObj o(BSON("foo" << 1 << "bar" << 2));
- ASSERT(isFieldRemovedByUpdate(o, "bar") == FieldRemovedStatus::kFieldNotRemoved);
- ASSERT(isFieldRemovedByUpdate(o, "baz") == FieldRemovedStatus::kUnknown);
+ extractNewValueForField(o, "foo");
}
-DEATH_TEST(UpdateOplogSerializationTest, CannotExtractDottedField, "cannot contain dots") {
+
+DEATH_TEST_REGEX(UpdateOplogSerializationTest, CannotExtractDottedField, "cannot contain dots") {
extractNewValueForField(BSONObj(), "a.b");
}
-DEATH_TEST(UpdateOplogSerializationTest, CannotReadDottedField, "cannot contain dots") {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest, CannotReadDottedField, "cannot contain dots") {
isFieldRemovedByUpdate(BSONObj(), "a.b");
}
-DEATH_TEST(UpdateOplogSerializationTest, CannotExtractFromNonExistentVersion, "Unrecognized") {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ CannotExtractFromNonExistentVersion,
+ "Tripwire assertion.*6448500") {
extractNewValueForField(BSON("$v" << 10), "a");
}
-DEATH_TEST(UpdateOplogSerializationTest, CannotReadNonExistentVersion, "Unrecognized") {
+DEATH_TEST_REGEX(UpdateOplogSerializationTest,
+ CannotReadNonExistentVersion,
+ "Tripwire assertion.*6448500") {
isFieldRemovedByUpdate(BSON("$v" << 10), "a");
}
} // namespace
diff --git a/src/mongo/db/update/update_oplog_entry_version.h b/src/mongo/db/update/update_oplog_entry_version.h
index cbd18e51834..983e7e16276 100644
--- a/src/mongo/db/update/update_oplog_entry_version.h
+++ b/src/mongo/db/update/update_oplog_entry_version.h
@@ -50,7 +50,7 @@ enum class UpdateOplogEntryVersion {
// user facing modifier-style update system remains. When a single update adds
// multiple fields, those fields are added in lexicographic order by field name. This system
// introduces support for arrayFilters and $[] syntax.
- kUpdateNodeV1 = 1,
+ kUpdateNodeV1_NotSupprted = 1,
// Delta style update, introduced in 4.7. When a pipeline based update is executed, the pre and
// post images are diffed, producing a delta. The delta is recorded in the oplog. On