summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGabriel Marks <gabriel.marks@mongodb.com>2022-09-13 16:28:37 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-09-13 20:02:43 +0000
commit293d41288fa7ccfbc03b8448b44214b2cf84db76 (patch)
tree34d00a7b53ab924a50de778d470ad412a472c5ed /src
parentfa534d676f5f673a6a7f3ea656f650ff108b7f92 (diff)
downloadmongo-293d41288fa7ccfbc03b8448b44214b2cf84db76.tar.gz
SERVER-68017 Constrain cluster-wide with-storage parameters to be tenant ID aware
Diffstat (limited to 'src')
-rw-r--r--src/mongo/db/change_collection_expired_documents_remover.cpp7
-rw-r--r--src/mongo/db/commands/set_cluster_parameter_invocation_test.cpp65
-rw-r--r--src/mongo/db/server_parameter.h3
-rw-r--r--src/mongo/db/server_parameter_with_storage.h11
-rw-r--r--src/mongo/idl/cluster_server_parameter_initializer_test.cpp18
-rw-r--r--src/mongo/idl/cluster_server_parameter_op_observer_test.cpp40
-rw-r--r--src/mongo/idl/server_parameter_with_storage_test.cpp80
7 files changed, 163 insertions, 61 deletions
diff --git a/src/mongo/db/change_collection_expired_documents_remover.cpp b/src/mongo/db/change_collection_expired_documents_remover.cpp
index 7c6a9b62eae..80a816945be 100644
--- a/src/mongo/db/change_collection_expired_documents_remover.cpp
+++ b/src/mongo/db/change_collection_expired_documents_remover.cpp
@@ -63,8 +63,11 @@ std::vector<boost::optional<TenantId>> getAllTenants() {
}
boost::optional<int64_t> getExpireAfterSeconds(boost::optional<TenantId> tid) {
- // TODO SERVER-65950 Fetch 'expiredAfterSeconds' per tenant basis.
- return {gChangeStreamsClusterParameter.getExpireAfterSeconds()};
+ auto* clusterParameters = ServerParameterSet::getClusterParameterSet();
+ auto* changeStreamsParam =
+ clusterParameters->get<ClusterParameterWithStorage<ChangeStreamsClusterParameterStorage>>(
+ "changeStreams");
+ return changeStreamsParam->getValue(tid).getExpireAfterSeconds();
}
void removeExpiredDocuments(Client* client) {
diff --git a/src/mongo/db/commands/set_cluster_parameter_invocation_test.cpp b/src/mongo/db/commands/set_cluster_parameter_invocation_test.cpp
index 3e99e94cf96..0623360a00e 100644
--- a/src/mongo/db/commands/set_cluster_parameter_invocation_test.cpp
+++ b/src/mongo/db/commands/set_cluster_parameter_invocation_test.cpp
@@ -99,7 +99,8 @@ private:
class DBClientMock : public DBClientService {
public:
- DBClientMock(std::function<StatusWith<bool>(BSONObj, BSONObj)> updateParameterOnDiskMock) {
+ DBClientMock(std::function<StatusWith<bool>(BSONObj, BSONObj, const boost::optional<TenantId>&)>
+ updateParameterOnDiskMock) {
this->updateParameterOnDiskMockImpl = updateParameterOnDiskMock;
}
@@ -108,7 +109,7 @@ public:
BSONObj info,
const WriteConcernOptions&,
const boost::optional<TenantId>& tenantId) override {
- return updateParameterOnDiskMockImpl(cmd, info);
+ return updateParameterOnDiskMockImpl(cmd, info, tenantId);
}
Timestamp getUpdateClusterTime(OperationContext*) override {
@@ -117,7 +118,8 @@ public:
}
private:
- std::function<StatusWith<bool>(BSONObj, BSONObj)> updateParameterOnDiskMockImpl;
+ std::function<StatusWith<bool>(BSONObj, BSONObj, const boost::optional<TenantId>&)>
+ updateParameterOnDiskMockImpl;
};
MockServerParameter alwaysValidatingServerParameter(StringData name) {
@@ -137,13 +139,22 @@ MockServerParameter alwaysInvalidatingServerParameter(StringData name) {
}
DBClientMock alwaysSucceedingDbClient() {
- DBClientMock dbServiceMock([&](BSONObj cmd, BSONObj info) { return true; });
+ DBClientMock dbServiceMock(
+ [&](BSONObj, BSONObj, const boost::optional<TenantId>&) { return true; });
+
+ return dbServiceMock;
+}
+
+DBClientMock tenantIdReportingDbClient() {
+ DBClientMock dbServiceMock([&](BSONObj, BSONObj, const boost::optional<TenantId>& tenantId) {
+ return Status(ErrorCodes::UnknownError, tenantId ? tenantId->toString() : "");
+ });
return dbServiceMock;
}
DBClientMock alwaysFailingDbClient() {
- DBClientMock dbServiceMock([&](BSONObj cmd, BSONObj info) {
+ DBClientMock dbServiceMock([&](BSONObj, BSONObj, const boost::optional<TenantId>&) {
return Status(ErrorCodes::UnknownError, "DB Client Update Failed");
});
@@ -300,5 +311,49 @@ TEST(SetClusterParameterCommand, ThrowsWhenParameterNotPresent) {
DBException,
ErrorCodes::NoSuchKey);
}
+
+TEST(SetClusterParameterCommand, TenantIdPassesThrough) {
+
+ DBClientMock dbServiceMock = tenantIdReportingDbClient();
+ MockServerParameter sp = alwaysValidatingServerParameter("TenantIdPassesThroughParameter"_sd);
+
+ auto serviceCtx = ServiceContext::make();
+ auto client = serviceCtx->makeClient("SomeTest");
+
+ auto mpsPtr = std::make_unique<MockParameterService>([&](StringData s) { return &sp; });
+
+ Client* clientPtr = client.get();
+
+ BSONObjBuilder testCmdBson;
+ testCmdBson << "testCommand"
+ << BSON("ok"
+ << "someval");
+
+ BSONObj obj = testCmdBson.obj();
+
+ SetClusterParameterInvocation fixture(std::move(mpsPtr), dbServiceMock);
+
+ OperationContext spyCtx(clientPtr, 1234);
+
+ TenantId tenantId(OID("123456789012345678901234"));
+
+ SetClusterParameter testCmdNoTenant(obj);
+
+ ASSERT_THROWS_CODE_AND_WHAT(
+ fixture.invoke(&spyCtx, testCmdNoTenant, boost::none, kMajorityWriteConcern),
+ DBException,
+ ErrorCodes::UnknownError,
+ "");
+
+ SetClusterParameter testCmdWithTenant(obj);
+ testCmdWithTenant.setDbName(NamespaceString::makeClusterParametersNSS(tenantId).dbName());
+
+ ASSERT_THROWS_CODE_AND_WHAT(
+ fixture.invoke(&spyCtx, testCmdWithTenant, boost::none, kMajorityWriteConcern),
+ DBException,
+ ErrorCodes::UnknownError,
+ tenantId.toString());
+}
+
} // namespace
} // namespace mongo
diff --git a/src/mongo/db/server_parameter.h b/src/mongo/db/server_parameter.h
index 0f69433e9f3..31ffd29ee2a 100644
--- a/src/mongo/db/server_parameter.h
+++ b/src/mongo/db/server_parameter.h
@@ -91,6 +91,9 @@ enum class ServerParameterType {
class ServerParameterSet;
class OperationContext;
+template <typename U>
+using TenantIdMap = std::map<boost::optional<TenantId>, U>;
+
class ServerParameter {
public:
using Map = std::map<std::string, ServerParameter*>;
diff --git a/src/mongo/db/server_parameter_with_storage.h b/src/mongo/db/server_parameter_with_storage.h
index 6e39fe27576..423509ae476 100644
--- a/src/mongo/db/server_parameter_with_storage.h
+++ b/src/mongo/db/server_parameter_with_storage.h
@@ -63,9 +63,6 @@ constexpr bool hasClusterServerParameter = stdx::is_detected_v<HasClusterServerP
namespace idl_server_parameter_detail {
-template <typename U>
-using TenantIdMap = std::map<boost::optional<TenantId>, U>;
-
// Predicate rules for bounds conditions
struct GT {
@@ -308,8 +305,8 @@ private:
public:
using element_type = typename SW::type;
- // TODO SERVER-68017 Tenant aware parameters are currently unsupported.
- static_assert(!SW::isTenantAware);
+ // Cluster parameters must be tenant-aware.
+ static_assert(SW::isTenantAware || paramType != SPT::kClusterWide);
// Compile-time assertion to ensure that IDL-defined in-memory storage for CSPs are
// chained to the ClusterServerParameter base type.
@@ -529,6 +526,10 @@ private:
std::once_flag _setDefaultOnce;
};
+template <typename Storage>
+using ClusterParameterWithStorage =
+ IDLServerParameterWithStorage<ServerParameterType::kClusterWide, TenantIdMap<Storage>>;
+
// MSVC has trouble resolving T=decltype(param) through the above class template.
// Avoid that by using this proxy factory to infer storage type.
template <ServerParameterType paramType, typename T>
diff --git a/src/mongo/idl/cluster_server_parameter_initializer_test.cpp b/src/mongo/idl/cluster_server_parameter_initializer_test.cpp
index fd9e1a8234d..f104f7e21d7 100644
--- a/src/mongo/idl/cluster_server_parameter_initializer_test.cpp
+++ b/src/mongo/idl/cluster_server_parameter_initializer_test.cpp
@@ -44,6 +44,8 @@ namespace mongo {
namespace {
using namespace cluster_server_parameter_test_util;
+typedef ClusterParameterWithStorage<ClusterServerParameterTest> ClusterTestParameter;
+
class ClusterServerParameterInitializerTest : public ClusterServerParameterTestBase {
public:
void setUp() final {
@@ -89,9 +91,7 @@ protected:
TEST_F(ClusterServerParameterInitializerTest, OnInitialSync) {
// Retrieve the in-memory test cluster server parameter and ensure it's set to the default
// value.
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
ClusterServerParameterTest cspTest = sp->getValue(boost::none);
ASSERT_EQ(cspTest.getIntValue(), kDefaultIntValue);
@@ -100,9 +100,7 @@ TEST_F(ClusterServerParameterInitializerTest, OnInitialSync) {
// Indicate that data is available at the end of initial sync and check that the in-memory data
// is updated.
doInitialSync();
- sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
cspTest = sp->getValue(boost::none);
ASSERT_EQ(cspTest.getIntValue(), kInitialIntValue);
@@ -111,9 +109,7 @@ TEST_F(ClusterServerParameterInitializerTest, OnInitialSync) {
TEST_F(ClusterServerParameterInitializerTest, OnStartupRecovery) {
// Retrieve the test cluster server parameter and ensure it's set to the default value.
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
ClusterServerParameterTest cspTest = sp->getValue(boost::none);
ASSERT_EQ(cspTest.getIntValue(), kDefaultIntValue);
@@ -122,9 +118,7 @@ TEST_F(ClusterServerParameterInitializerTest, OnStartupRecovery) {
// Indicate that data is available at the end of startup recovery and check that the in-memory
// data is updated.
doStartupRecovery();
- sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
cspTest = sp->getValue(boost::none);
ASSERT_EQ(cspTest.getIntValue(), kInitialIntValue);
diff --git a/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp b/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp
index 3b149fdae2c..87efd29a2a9 100644
--- a/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp
+++ b/src/mongo/idl/cluster_server_parameter_op_observer_test.cpp
@@ -45,6 +45,8 @@ const std::vector<NamespaceString> kIgnoredNamespaces = {
NamespaceString("local"_sd, "clusterParameters"_sd),
NamespaceString("test"_sd, "foo"_sd)};
+typedef ClusterParameterWithStorage<ClusterServerParameterTest> ClusterTestParameter;
+
class ClusterServerParameterOpObserverTest : public ClusterServerParameterTestBase {
public:
void setUp() override {
@@ -128,9 +130,8 @@ public:
// Asserts that the parameter state does not change for this action.
template <typename F>
void assertIgnored(const NamespaceString& nss, F fn) {
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp =
+ ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
const auto initialCPTime = sp->getClusterParameterTime(boost::none);
@@ -151,9 +152,8 @@ public:
upsert(doc);
doInserts(NamespaceString::kClusterParametersNamespace, {doc});
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp =
+ ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
ClusterServerParameterTest cspTest = sp->getValue(boost::none);
@@ -183,9 +183,7 @@ protected:
};
TEST_F(ClusterServerParameterOpObserverTest, OnInsertRecord) {
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
// Single record insert.
@@ -251,9 +249,7 @@ TEST_F(ClusterServerParameterOpObserverTest, OnInsertRecord) {
TEST_F(ClusterServerParameterOpObserverTest, OnUpdateRecord) {
initializeState();
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
// Single record update.
@@ -283,9 +279,7 @@ TEST_F(ClusterServerParameterOpObserverTest, OnUpdateRecord) {
}
TEST_F(ClusterServerParameterOpObserverTest, onDeleteRecord) {
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
const auto initialDoc = initializeState();
@@ -328,9 +322,7 @@ TEST_F(ClusterServerParameterOpObserverTest, onDropDatabase) {
// Actually drop the config DB.
doDropDatabase(kConfigDB);
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
ClusterServerParameterTest cspTest = sp->getValue(boost::none);
@@ -346,9 +338,7 @@ TEST_F(ClusterServerParameterOpObserverTest, onRenameCollection) {
assertIgnoredOtherNamespaces([&](const auto& nss) { doRenameCollection(nss, kTestFoo); });
assertIgnoredOtherNamespaces([&](const auto& nss) { doRenameCollection(kTestFoo, nss); });
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
// These renames "work" despite not mutating durable state
@@ -374,9 +364,7 @@ TEST_F(ClusterServerParameterOpObserverTest, onImportCollection) {
// Import ignorable collections.
assertIgnoredOtherNamespaces([&](const auto& nss) { doImportCollection(nss); });
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
// Import the collection (rescan).
@@ -396,9 +384,7 @@ TEST_F(ClusterServerParameterOpObserverTest, onReplicationRollback) {
// Import ignorable collections.
assertIgnoredOtherNamespaces([&](const auto& nss) { doImportCollection(nss); });
- auto* sp = ServerParameterSet::getClusterParameterSet()
- ->get<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- ClusterServerParameterTest>>(kCSPTest);
+ auto* sp = ServerParameterSet::getClusterParameterSet()->get<ClusterTestParameter>(kCSPTest);
ASSERT(sp != nullptr);
// Trigger rollback of ignorable namespaces.
diff --git a/src/mongo/idl/server_parameter_with_storage_test.cpp b/src/mongo/idl/server_parameter_with_storage_test.cpp
index b9a22ed689b..3944c9e0ce0 100644
--- a/src/mongo/idl/server_parameter_with_storage_test.cpp
+++ b/src/mongo/idl/server_parameter_with_storage_test.cpp
@@ -327,8 +327,7 @@ TEST(IDLServerParameterWithStorage, RAIIServerParameterController) {
TEST(IDLServerParameterWithStorage, CSPStorageTest) {
// Retrieve the cluster IDLServerParameterWithStorage.
auto* clusterParam =
- dynamic_cast<IDLServerParameterWithStorage<ServerParameterType::kClusterWide,
- test::ChangeStreamOptionsClusterParam>*>(
+ dynamic_cast<ClusterParameterWithStorage<test::ChangeStreamOptionsClusterParam>*>(
getClusterServerParameter("changeStreamOptions"));
// Check that current value is the default value.
@@ -360,14 +359,16 @@ TEST(IDLServerParameterWithStorage, CSPStorageTest) {
ASSERT_EQ(test::count, 1);
// Append to BSONObj and verify that expected fields are present.
- BSONObjBuilder b;
- clusterParam->append(nullptr, &b, clusterParam->name(), boost::none);
- auto obj = b.obj();
- ASSERT_EQ(obj.nFields(), 4);
- ASSERT_EQ(obj["_id"_sd].String(), "changeStreamOptions");
- ASSERT_EQ(obj["preAndPostImages"_sd].Obj()["expireAfterSeconds"].Long(), 40);
- ASSERT_EQ(obj["testStringField"_sd].String(), "testString");
- ASSERT_EQ(obj["clusterParameterTime"_sd].timestamp(), updateTime.asTimestamp());
+ {
+ BSONObjBuilder b;
+ clusterParam->append(nullptr, &b, clusterParam->name(), boost::none);
+ auto obj = b.obj();
+ ASSERT_EQ(obj.nFields(), 4);
+ ASSERT_EQ(obj["_id"_sd].String(), "changeStreamOptions");
+ ASSERT_EQ(obj["preAndPostImages"_sd].Obj()["expireAfterSeconds"].Long(), 40);
+ ASSERT_EQ(obj["testStringField"_sd].String(), "testString");
+ ASSERT_EQ(obj["clusterParameterTime"_sd].timestamp(), updateTime.asTimestamp());
+ }
// setFromString should fail for cluster server parameters.
ASSERT_NOT_OK(clusterParam->setFromString("", boost::none));
@@ -417,6 +418,65 @@ TEST(IDLServerParameterWithStorage, CSPStorageTest) {
ASSERT_EQ(retrievedParam.getTestStringField(), "default");
ASSERT_EQ(clusterParam->getClusterParameterTime(boost::none), LogicalTime::kUninitialized);
ASSERT_EQ(test::count, 3);
+
+ // Different tenants should access separate sets of cluster parameters.
+ auto tenant1 = TenantId(OID("1234567890abcdef12345678"));
+ auto tenant2 = TenantId(OID("1234567890abcdef12345679"));
+
+ // New tenants should start w/ the defaults.
+ auto retrievedParam1 = clusterParam->getValue(tenant1);
+ auto retrievedParam2 = clusterParam->getValue(tenant2);
+ ASSERT_EQ(retrievedParam1.getPreAndPostImages().getExpireAfterSeconds(), 35);
+ ASSERT_EQ(retrievedParam2.getPreAndPostImages().getExpireAfterSeconds(), 35);
+
+ // Setting for one tenant should not change any other tenants.
+ ASSERT_OK(clusterParam->ServerParameter::set(newDefaultParam.toBSON(), tenant1));
+ retrievedParam = clusterParam->getValue(boost::none);
+ retrievedParam1 = clusterParam->getValue(tenant1);
+ retrievedParam2 = clusterParam->getValue(tenant2);
+ ASSERT_EQ(retrievedParam.getPreAndPostImages().getExpireAfterSeconds(), 35);
+ ASSERT_EQ(retrievedParam1.getPreAndPostImages().getExpireAfterSeconds(), 45);
+ ASSERT_EQ(retrievedParam2.getPreAndPostImages().getExpireAfterSeconds(), 35);
+
+ updatedPrePostImgs.setExpireAfterSeconds(40);
+ updatedParam.setPreAndPostImages(updatedPrePostImgs);
+ ASSERT_OK(clusterParam->ServerParameter::set(updatedParam.toBSON(), boost::none));
+ retrievedParam = clusterParam->getValue(boost::none);
+ retrievedParam1 = clusterParam->getValue(tenant1);
+ retrievedParam2 = clusterParam->getValue(tenant2);
+ ASSERT_EQ(retrievedParam.getPreAndPostImages().getExpireAfterSeconds(), 40);
+ ASSERT_EQ(retrievedParam1.getPreAndPostImages().getExpireAfterSeconds(), 45);
+ ASSERT_EQ(retrievedParam2.getPreAndPostImages().getExpireAfterSeconds(), 35);
+
+ // Resetting one tenant should not change any other tenants.
+ ASSERT_OK(clusterParam->reset(tenant1));
+ retrievedParam = clusterParam->getValue(boost::none);
+ retrievedParam1 = clusterParam->getValue(tenant1);
+ retrievedParam2 = clusterParam->getValue(tenant2);
+ ASSERT_EQ(retrievedParam.getPreAndPostImages().getExpireAfterSeconds(), 40);
+ ASSERT_EQ(retrievedParam1.getPreAndPostImages().getExpireAfterSeconds(), 35);
+ ASSERT_EQ(retrievedParam2.getPreAndPostImages().getExpireAfterSeconds(), 35);
+
+ // Append should append only the tenant specified.
+ ASSERT_OK(clusterParam->ServerParameter::set(newDefaultParam.toBSON(), tenant2));
+ {
+ BSONObjBuilder b;
+ clusterParam->append(nullptr, &b, clusterParam->name(), boost::none);
+ auto obj = b.obj();
+ ASSERT_EQ(obj["preAndPostImages"_sd].Obj()["expireAfterSeconds"].Long(), 40);
+ }
+ {
+ BSONObjBuilder b;
+ clusterParam->append(nullptr, &b, clusterParam->name(), tenant1);
+ auto obj = b.obj();
+ ASSERT_EQ(obj["preAndPostImages"_sd].Obj()["expireAfterSeconds"].Long(), 35);
+ }
+ {
+ BSONObjBuilder b;
+ clusterParam->append(nullptr, &b, clusterParam->name(), tenant2);
+ auto obj = b.obj();
+ ASSERT_EQ(obj["preAndPostImages"_sd].Obj()["expireAfterSeconds"].Long(), 45);
+ }
}
} // namespace