summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlison Lu <alison.lu@mongodb.com>2021-08-18 18:27:14 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2021-08-20 18:40:35 +0000
commit4b0a8462ea40883c40565216f349390fe49d822d (patch)
treedd29369a895fafe5d4cda4e588bc926b8b476886
parent7f4e9553fb617354cabedf6ad6304934e6688efc (diff)
downloadmongo-4b0a8462ea40883c40565216f349390fe49d822d.tar.gz
SERVER-59024 Unit test update functions in timeseries_update_delete_util.h
-rw-r--r--src/mongo/db/timeseries/timeseries_update_delete_util.cpp2
-rw-r--r--src/mongo/db/timeseries/timeseries_update_delete_util_test.cpp164
2 files changed, 165 insertions, 1 deletions
diff --git a/src/mongo/db/timeseries/timeseries_update_delete_util.cpp b/src/mongo/db/timeseries/timeseries_update_delete_util.cpp
index 79a849faf30..01cfceb20a8 100644
--- a/src/mongo/db/timeseries/timeseries_update_delete_util.cpp
+++ b/src/mongo/db/timeseries/timeseries_update_delete_util.cpp
@@ -167,7 +167,7 @@ bool updateOnlyModifiesMetaField(OperationContext* opCtx,
StringData metaField) {
invariant(updateMod.type() != write_ops::UpdateModification::Type::kDelta);
uassert(ErrorCodes::InvalidOptions,
- str::stream() << "Pipeline upddates are not supported for time-series collections: "
+ str::stream() << "Pipeline updates are not supported for time-series collections: "
<< ns,
updateMod.type() != write_ops::UpdateModification::Type::kPipeline);
diff --git a/src/mongo/db/timeseries/timeseries_update_delete_util_test.cpp b/src/mongo/db/timeseries/timeseries_update_delete_util_test.cpp
index 9f398661e6b..6d713b9db07 100644
--- a/src/mongo/db/timeseries/timeseries_update_delete_util_test.cpp
+++ b/src/mongo/db/timeseries/timeseries_update_delete_util_test.cpp
@@ -28,11 +28,13 @@
*/
+#include "mongo/base/error_codes.h"
#include "mongo/bson/bsonobj.h"
#include "mongo/db/pipeline/document_source_merge_gen.h"
#include "mongo/db/pipeline/legacy_runtime_constants_gen.h"
#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/db/timeseries/timeseries_update_delete_util.h"
+#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
#include "mongo/util/assert_util.h"
@@ -46,6 +48,14 @@ protected:
_opCtx = cc().makeOperationContext();
}
+ void _testClassicUpdateTranslation(const BSONObj& originalUpdate,
+ const BSONObj& expectedTranslatedUpdate) {
+ auto res = timeseries::translateUpdate(
+ write_ops::UpdateModification::parseFromClassicUpdate(originalUpdate), _metaField);
+ ASSERT(res.type() == write_ops::UpdateModification::Type::kClassic);
+ ASSERT_BSONOBJ_EQ(res.getUpdateClassic(), expectedTranslatedUpdate);
+ }
+
ServiceContext::UniqueOperationContext _opCtx;
StringData _metaField = "tag";
NamespaceString _ns{"timeseries_update_delete_util_test", "system.buckets.t"};
@@ -330,5 +340,159 @@ TEST_F(TimeseriesUpdateDeleteUtilTest, TranslateQuery) {
<< BSON("meta" << BSON("b"
<< "B")))));
}
+
+TEST_F(TimeseriesUpdateDeleteUtilTest, UpdateOnlyModifiesMetaField) {
+ // {$set: {tag: "A"}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$set" << BSON(_metaField << "A"))),
+ _metaField));
+
+ // {$set: {nonMetaField: "A"}}
+ ASSERT_FALSE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(BSON("$set" << BSON("nonMetaField"
+ << "A"))),
+ _metaField));
+
+ // {$set: {tag.a: "A"}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(BSON("$set" << BSON(_metaField + ".a"
+ << "A"))),
+ _metaField));
+
+ // {$unset: {tag.a: ""}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$unset" << BSON(_metaField + ".a"
+ << ""))),
+ _metaField));
+
+ // {$unset: {tag.a: ""}, {$inc: {nonMetaField: 10}}}
+ ASSERT_FALSE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$unset" << BSON(_metaField + ".a"
+ << "")
+ << "inc" << BSON("nonMetaField" << 10))),
+ _metaField));
+
+ // {$unset: {tag.a: ""}, {$inc: {tagggg: 10}}}
+ ASSERT_FALSE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$unset" << BSON(_metaField + ".a"
+ << "")
+ << "inc" << BSON(_metaField + "ggg" << 10))),
+ _metaField));
+
+ // {$rename: {"tag.a.a": "A", "tag.b": "B"}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$rename" << BSON(_metaField + ".a.a"
+ << "A" << _metaField + ".b"
+ << "B"))),
+ _metaField));
+
+ // {$rename: {tag.tag.tag: 8}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$rename" << BSON(_metaField + "." + _metaField + "." + _metaField << 8))),
+ _metaField));
+
+ // {$set: {tag.$: 100}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(BSON("$set" << BSON(_metaField + ".$"
+ << ""))),
+ _metaField));
+
+ // {$pull: {tag.arr: {$gte: 80}}}
+ ASSERT_TRUE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$pull" << BSON(_metaField + ".arr" << BSON("gte" << 80)))),
+ _metaField));
+
+ // Update a collection that does not have a metaField.
+ // {$inc: {nonMetaField: ""}}
+ ASSERT_FALSE(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(),
+ _ns,
+ write_ops::UpdateModification::parseFromClassicUpdate(BSON("$inc" << BSON("nonMetaField"
+ << ""))),
+ StringData()));
+
+ // Update with an empty document, which is considered a replacement document.
+ ASSERT_THROWS(timeseries::updateOnlyModifiesMetaField(
+ _opCtx.get(), _ns, write_ops::UpdateModification(), _metaField),
+ ExceptionFor<ErrorCodes::InvalidOptions>);
+}
+
+TEST_F(TimeseriesUpdateDeleteUtilTest, TranslateUpdate) {
+ // {$set: {nonMetaField: "A"}} => {$set: {nonMetaField: "A"}}
+ _testClassicUpdateTranslation(BSON("$set" << BSON("nonMetaField"
+ << "A")),
+ BSON("$set" << BSON("nonMetaField"
+ << "A")));
+
+ // {$set: {tag: "A"}} => {$set: {meta: "A"}}
+ _testClassicUpdateTranslation(BSON("$set" << BSON(_metaField << "A")),
+ BSON("$set" << BSON("meta"
+ << "A")));
+
+ // {$unset: {tag.a: ""}, {$inc: {nonMetaField: 10}}} =>
+ // {$unset: {meta.a: ""}, {$inc: {nonMetaField: 10}}}
+ _testClassicUpdateTranslation(BSON("$unset" << BSON(_metaField + ".a"
+ << "")
+ << "inc" << BSON("nonMetaField" << 10)),
+ BSON("$unset" << BSON("meta.a"
+ << "")
+ << "inc" << BSON("nonMetaField" << 10)));
+
+ // {$rename: {"tag.a.a": "A", "tag.b": "B"}}
+ _testClassicUpdateTranslation(BSON("$rename" << BSON(_metaField + ".a.a"
+ << "A" << _metaField + ".b"
+ << "B")),
+ BSON("$rename" << BSON("meta.a.a"
+ << "A"
+ << "meta.b"
+ << "B")));
+
+ // {$rename: {tag.tag.tag: 8}}
+ _testClassicUpdateTranslation(
+ BSON("$rename" << BSON(_metaField + "." + _metaField + "." + _metaField << 8)),
+ BSON("$rename" << BSON("meta.tag.tag" << 8)));
+}
+
+// Translate an update with an empty metaField, which violates the translation method's
+// precondition.
+DEATH_TEST_F(TimeseriesUpdateDeleteUtilTest,
+ TranslateUpdateWithEmptyMetaField,
+ "Invariant failure") {
+ timeseries::translateUpdate(write_ops::UpdateModification::parseFromClassicUpdate(
+ BSON("$set" << BSON(_metaField << "A"))),
+ StringData());
+}
+
+// Translate an empty update, which is considered a replacement document.
+DEATH_TEST_F(TimeseriesUpdateDeleteUtilTest, TranslateEmptyUpdate, "Invariant failure") {
+ timeseries::translateUpdate(write_ops::UpdateModification(), _metaField);
+}
} // namespace
} // namespace mongo