summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mongo/SConscript3
-rw-r--r--src/mongo/db/pipeline/accumulator_js_test.cpp1
-rw-r--r--src/mongo/db/pipeline/expression_javascript_test.cpp1
-rw-r--r--src/mongo/db/query/find_and_modify_request_test.cpp3
-rw-r--r--src/mongo/db/s/wait_for_ongoing_chunk_splits_command.cpp8
-rw-r--r--src/mongo/dbtests/dbtests.cpp2
-rw-r--r--src/mongo/executor/SConscript1
-rw-r--r--src/mongo/executor/network_interface_integration_test.cpp1
-rw-r--r--src/mongo/executor/network_interface_tl.cpp4
-rw-r--r--src/mongo/shell/mongo_main.cpp9
-rw-r--r--src/mongo/shell/servers.js8
-rw-r--r--src/mongo/shell/utils.js5
-rw-r--r--src/mongo/unittest/SConscript2
-rw-r--r--src/mongo/unittest/integration_test_main.cpp4
-rw-r--r--src/mongo/unittest/unittest_main.cpp4
-rw-r--r--src/mongo/util/SConscript13
-rw-r--r--src/mongo/util/latch_analyzer.cpp8
-rw-r--r--src/mongo/util/latch_analyzer_test.cpp12
-rw-r--r--src/mongo/util/testing_options.cpp66
-rw-r--r--src/mongo/util/testing_options.idl38
-rw-r--r--src/mongo/util/testing_proctor.cpp80
-rw-r--r--src/mongo/util/testing_proctor.h67
22 files changed, 299 insertions, 41 deletions
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index 5b1aecdb10d..ee959b26226 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -159,6 +159,7 @@ baseEnv.Library(
'util/system_clock_source.cpp',
'util/system_tick_source.cpp',
'util/text.cpp',
+ 'util/testing_proctor.cpp',
'util/thread_safety_context.cpp',
'util/time_support.cpp',
'util/timer.cpp',
@@ -499,6 +500,7 @@ env.Library(
'util/ntservice',
'util/options_parser/options_parser_init',
'util/periodic_runner_factory',
+ 'util/testing_options',
'util/version_impl',
'watchdog/watchdog_mongod',
],
@@ -704,6 +706,7 @@ env.Library(
'util/ntservice',
'util/options_parser/options_parser',
'util/options_parser/options_parser_init',
+ 'util/testing_options',
'util/version_impl',
],
LIBDEPS=[
diff --git a/src/mongo/db/pipeline/accumulator_js_test.cpp b/src/mongo/db/pipeline/accumulator_js_test.cpp
index 6ce4adae7c9..92e11e592a8 100644
--- a/src/mongo/db/pipeline/accumulator_js_test.cpp
+++ b/src/mongo/db/pipeline/accumulator_js_test.cpp
@@ -62,7 +62,6 @@ private:
void MapReduceFixture::setUp() {
- setTestCommandsEnabled(true);
ServiceContextMongoDTest::setUp();
ScriptEngine::setup(false);
}
diff --git a/src/mongo/db/pipeline/expression_javascript_test.cpp b/src/mongo/db/pipeline/expression_javascript_test.cpp
index 299ee506664..dc0df7cb51d 100644
--- a/src/mongo/db/pipeline/expression_javascript_test.cpp
+++ b/src/mongo/db/pipeline/expression_javascript_test.cpp
@@ -75,7 +75,6 @@ private:
void MapReduceFixture::setUp() {
- setTestCommandsEnabled(true);
ServiceContextMongoDTest::setUp();
ScriptEngine::setup(false);
}
diff --git a/src/mongo/db/query/find_and_modify_request_test.cpp b/src/mongo/db/query/find_and_modify_request_test.cpp
index a5d55fcd503..f9f01b82769 100644
--- a/src/mongo/db/query/find_and_modify_request_test.cpp
+++ b/src/mongo/db/query/find_and_modify_request_test.cpp
@@ -53,7 +53,6 @@ TEST(FindAndModifyRequest, BasicUpdate) {
}
TEST(FindAndModifyRequest, PipelineUpdate) {
- setTestCommandsEnabled(true);
const BSONObj query(BSON("x" << 1));
const BSONObj pipelineBSON(
BSON("pipeline" << BSON_ARRAY(BSON("$addFields" << BSON("y" << 1)))));
@@ -660,7 +659,6 @@ TEST(FindAndModifyRequest, ParseWithWriteConcernAsArray) {
}
TEST(FindAndModifyRequest, ParsesAndSerializesPipelineUpdate) {
- setTestCommandsEnabled(true);
BSONObj cmdObj(fromjson(R"json({
query: { x: 1 },
update: [{$replaceWith: {y: 1}}]
@@ -684,7 +682,6 @@ TEST(FindAndModifyRequest, ParsesAndSerializesPipelineUpdate) {
}
TEST(FindAndModifyRequest, RejectsBothArrayFiltersAndPipelineUpdate) {
- setTestCommandsEnabled(true);
BSONObj cmdObj(fromjson(R"json({
query: { x: 1 },
update: [{$replaceWith: {y: 1}}],
diff --git a/src/mongo/db/s/wait_for_ongoing_chunk_splits_command.cpp b/src/mongo/db/s/wait_for_ongoing_chunk_splits_command.cpp
index f9b1e85a78c..04a0e6dce92 100644
--- a/src/mongo/db/s/wait_for_ongoing_chunk_splits_command.cpp
+++ b/src/mongo/db/s/wait_for_ongoing_chunk_splits_command.cpp
@@ -83,12 +83,6 @@ public:
}
};
-MONGO_INITIALIZER(RegisterWaitForOngoingChunkSplitsCommand)(InitializerContext* context) {
- if (getTestCommandsEnabled()) {
- // Leaked intentionally: a Command registers itself when constructed.
- new WaitForOngoingChunksSplitsCommand();
- }
- return Status::OK();
-}
+MONGO_REGISTER_TEST_COMMAND(WaitForOngoingChunksSplitsCommand);
} // namespace
} // namespace mongo
diff --git a/src/mongo/dbtests/dbtests.cpp b/src/mongo/dbtests/dbtests.cpp
index 9f4d4b63984..03a3eb6fd01 100644
--- a/src/mongo/dbtests/dbtests.cpp
+++ b/src/mongo/dbtests/dbtests.cpp
@@ -59,6 +59,7 @@
#include "mongo/util/clock_source_mock.h"
#include "mongo/util/quick_exit.h"
#include "mongo/util/signal_handlers_synchronous.h"
+#include "mongo/util/testing_proctor.h"
#include "mongo/util/text.h"
namespace mongo {
@@ -173,6 +174,7 @@ WriteContextForTests::WriteContextForTests(OperationContext* opCtx, StringData n
int dbtestsMain(int argc, char** argv, char** envp) {
::mongo::setTestCommandsEnabled(true);
+ ::mongo::TestingProctor::instance().setEnabled(true);
::mongo::setupSynchronousSignalHandlers();
mongo::dbtests::initWireSpec();
diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript
index a6b306f0596..25b6ec650d5 100644
--- a/src/mongo/executor/SConscript
+++ b/src/mongo/executor/SConscript
@@ -134,7 +134,6 @@ env.Library(
'hedging_metrics',
],
LIBDEPS_PRIVATE=[
- '$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/transport/transport_layer_manager',
'connection_pool_executor',
'network_interface',
diff --git a/src/mongo/executor/network_interface_integration_test.cpp b/src/mongo/executor/network_interface_integration_test.cpp
index 9a0e31f08b9..36d0b6aae60 100644
--- a/src/mongo/executor/network_interface_integration_test.cpp
+++ b/src/mongo/executor/network_interface_integration_test.cpp
@@ -161,7 +161,6 @@ public:
}
void setUp() override {
- setTestCommandsEnabled(true);
startNet(std::make_unique<WaitForIsMasterHook>(this));
}
diff --git a/src/mongo/executor/network_interface_tl.cpp b/src/mongo/executor/network_interface_tl.cpp
index 48adfb7d4fa..647fc1bfb36 100644
--- a/src/mongo/executor/network_interface_tl.cpp
+++ b/src/mongo/executor/network_interface_tl.cpp
@@ -33,7 +33,6 @@
#include "mongo/executor/network_interface_tl.h"
-#include "mongo/db/commands/test_commands_enabled.h"
#include "mongo/db/server_options.h"
#include "mongo/executor/connection_pool_tl.h"
#include "mongo/executor/hedging_metrics.h"
@@ -42,6 +41,7 @@
#include "mongo/transport/transport_layer_manager.h"
#include "mongo/util/concurrency/idle_thread_block.h"
#include "mongo/util/net/socket_utils.h"
+#include "mongo/util/testing_proctor.h"
namespace mongo {
namespace executor {
@@ -129,7 +129,7 @@ NetworkInterfaceTL::NetworkInterfaceTL(std::string instanceName,
_pool = std::make_shared<ConnectionPool>(
std::move(typeFactory), std::string("NetworkInterfaceTL-") + _instanceName, _connPoolOpts);
- if (getTestCommandsEnabled()) {
+ if (TestingProctor::instance().isEnabled()) {
_counters = std::make_unique<SynchronizedCounters>();
}
}
diff --git a/src/mongo/shell/mongo_main.cpp b/src/mongo/shell/mongo_main.cpp
index a7051081d3f..c338fe921d7 100644
--- a/src/mongo/shell/mongo_main.cpp
+++ b/src/mongo/shell/mongo_main.cpp
@@ -55,7 +55,6 @@
#include "mongo/config.h"
#include "mongo/db/auth/sasl_command_constants.h"
#include "mongo/db/client.h"
-#include "mongo/db/commands/test_commands_enabled.h"
#include "mongo/db/log_process_details.h"
#include "mongo/db/server_options.h"
#include "mongo/logger/console_appender.h"
@@ -125,14 +124,6 @@ MONGO_INITIALIZER_WITH_PREREQUISITES(SetFeatureCompatibilityVersionLatest,
return Status::OK();
}
-// Initialize the testCommandsEnabled server parameter to true since the mongo shell does not have
-// any test-only commands that could cause harm to the server, and it may be necessary to enable
-// this to test certain features, for example through benchRun (see SERVER-40419).
-MONGO_INITIALIZER_WITH_PREREQUISITES(EnableShellTestCommands, ("EndStartupOptionSetup"))
-(InitializerContext* context) {
- setTestCommandsEnabled(true);
- return Status::OK();
-}
const auto kAuthParam = "authSource"s;
/**
diff --git a/src/mongo/shell/servers.js b/src/mongo/shell/servers.js
index 6170046a15d..dd2a46dfdcc 100644
--- a/src/mongo/shell/servers.js
+++ b/src/mongo/shell/servers.js
@@ -1126,6 +1126,14 @@ function appendSetParameterArgs(argArray) {
if (jsTest.options().enableTestCommands) {
argArray.push(...['--setParameter', "enableTestCommands=1"]);
}
+
+ // TODO SERVER-46726 include v4.4 once SERVER-46726 is backported to v4.4
+ if (!programMajorMinorVersion || programMajorMinorVersion > 404) {
+ if (jsTest.options().testingDiagnosticsEnabled) {
+ argArray.push(...['--setParameter', "testingDiagnosticsEnabled=1"]);
+ }
+ }
+
if (jsTest.options().authMechanism && jsTest.options().authMechanism != "SCRAM-SHA-1") {
if (!argArrayContainsSetParameterValue('authenticationMechanisms=')) {
argArray.push(...['--setParameter',
diff --git a/src/mongo/shell/utils.js b/src/mongo/shell/utils.js
index 4b905500e2e..125b9aeac26 100644
--- a/src/mongo/shell/utils.js
+++ b/src/mongo/shell/utils.js
@@ -268,6 +268,11 @@ jsTestOptions = function() {
// TestData
enableTestCommands:
TestData.hasOwnProperty('enableTestCommands') ? TestData.enableTestCommands : true,
+ // Testing diagnostics should be enabled by default if no testingDiagnosticsEnabled was
+ // present in TestData
+ testingDiagnosticsEnabled: TestData.hasOwnProperty('testingDiagnosticsEnabled')
+ ? TestData.testingDiagnosticsEnabled
+ : true,
serviceExecutor: TestData.serviceExecutor,
setParameters: TestData.setParameters,
setParametersMongos: TestData.setParametersMongos,
diff --git a/src/mongo/unittest/SConscript b/src/mongo/unittest/SConscript
index f7691b0c5cd..517a1de6997 100644
--- a/src/mongo/unittest/SConscript
+++ b/src/mongo/unittest/SConscript
@@ -35,6 +35,7 @@ env.Library(
'unittest',
],
LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/util/options_parser/options_parser',
],
)
@@ -51,6 +52,7 @@ env.Library(
],
LIBDEPS_PRIVATE=[
'$BUILD_DIR/mongo/client/connection_string',
+ '$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/db/serverinit',
'$BUILD_DIR/mongo/db/server_options',
'$BUILD_DIR/mongo/db/server_options_base',
diff --git a/src/mongo/unittest/integration_test_main.cpp b/src/mongo/unittest/integration_test_main.cpp
index f850fdc901e..07f8c95b097 100644
--- a/src/mongo/unittest/integration_test_main.cpp
+++ b/src/mongo/unittest/integration_test_main.cpp
@@ -37,6 +37,7 @@
#include "mongo/base/initializer.h"
#include "mongo/client/connection_string.h"
+#include "mongo/db/commands/test_commands_enabled.h"
#include "mongo/db/server_options_base.h"
#include "mongo/db/server_options_helpers.h"
#include "mongo/db/service_context.h"
@@ -51,6 +52,7 @@
#include "mongo/util/options_parser/startup_options.h"
#include "mongo/util/quick_exit.h"
#include "mongo/util/signal_handlers_synchronous.h"
+#include "mongo/util/testing_proctor.h"
using namespace mongo;
@@ -72,7 +74,9 @@ ConnectionString getFixtureConnectionString() {
int main(int argc, char** argv, char** envp) {
setupSynchronousSignalHandlers();
+ TestingProctor::instance().setEnabled(true);
runGlobalInitializersOrDie(argc, argv, envp);
+ setTestCommandsEnabled(true);
setGlobalServiceContext(ServiceContext::make());
quickExit(unittest::Suite::run(std::vector<std::string>(), "", "", 1));
}
diff --git a/src/mongo/unittest/unittest_main.cpp b/src/mongo/unittest/unittest_main.cpp
index 1472cdbe2f8..39e59923d10 100644
--- a/src/mongo/unittest/unittest_main.cpp
+++ b/src/mongo/unittest/unittest_main.cpp
@@ -33,6 +33,7 @@
#include "mongo/base/initializer.h"
#include "mongo/base/status.h"
+#include "mongo/db/commands/test_commands_enabled.h"
#include "mongo/logger/logger.h"
#include "mongo/logv2/log_domain_global.h"
#include "mongo/logv2/log_manager.h"
@@ -43,6 +44,7 @@
#include "mongo/util/options_parser/option_section.h"
#include "mongo/util/options_parser/options_parser.h"
#include "mongo/util/signal_handlers_synchronous.h"
+#include "mongo/util/testing_proctor.h"
using mongo::Status;
@@ -52,7 +54,9 @@ int main(int argc, char** argv, char** envp) {
::mongo::clearSignalMask();
::mongo::setupSynchronousSignalHandlers();
+ ::mongo::TestingProctor::instance().setEnabled(true);
::mongo::runGlobalInitializersOrDie(argc, argv, envp);
+ ::mongo::setTestCommandsEnabled(true);
moe::OptionSection options;
diff --git a/src/mongo/util/SConscript b/src/mongo/util/SConscript
index 2ec5e638b83..dd5edaf76c8 100644
--- a/src/mongo/util/SConscript
+++ b/src/mongo/util/SConscript
@@ -158,6 +158,18 @@ env.Library(
)
env.Library(
+ target="testing_options",
+ source=[
+ "testing_options.cpp",
+ env.Idlc('testing_options.idl')[0],
+ ],
+ LIBDEPS=[
+ "$BUILD_DIR/mongo/base",
+ "$BUILD_DIR/mongo/idl/server_parameter",
+ ],
+)
+
+env.Library(
target="periodic_runner",
source=[
"periodic_runner.cpp",
@@ -316,7 +328,6 @@ if get_option('use-diagnostic-latches') == 'on':
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
- '$BUILD_DIR/mongo/db/commands/test_commands_enabled',
'$BUILD_DIR/mongo/db/service_context',
],
LIBDEPS_PRIVATE=[
diff --git a/src/mongo/util/latch_analyzer.cpp b/src/mongo/util/latch_analyzer.cpp
index 760ecd265cb..c7ef2e57a1e 100644
--- a/src/mongo/util/latch_analyzer.cpp
+++ b/src/mongo/util/latch_analyzer.cpp
@@ -42,12 +42,12 @@
#include "mongo/base/init.h"
#include "mongo/db/client.h"
-#include "mongo/db/commands/test_commands_enabled.h"
#include "mongo/db/service_context.h"
#include "mongo/logv2/log.h"
#include "mongo/platform/mutex.h"
#include "mongo/util/fail_point.h"
#include "mongo/util/latch_analyzer.h"
+#include "mongo/util/testing_proctor.h"
namespace mongo {
@@ -126,7 +126,7 @@ struct LatchSetState {
using LatchIdentitySet = std::deque<const latch_detail::Identity*>;
LatchSetState() {
- if (getTestCommandsEnabled()) {
+ if (TestingProctor::instance().isEnabled()) {
identities = std::make_unique<LatchIdentitySet>();
}
}
@@ -139,7 +139,7 @@ struct LatchSetState {
// This is an ordered list of latch Identities. Each acquired Latch will add itself to the end
// of this list and each released Latch will remove itself from the end. This is populated when
- // getTestCommandsEnabled() is true, i.e. in a testing environment.
+ // TestingProctor::instance().isEnabled() is true, i.e. in a testing environment.
std::unique_ptr<LatchIdentitySet> identities;
};
@@ -166,7 +166,7 @@ void LatchAnalyzer::setAllowExitOnViolation(bool allowExitOnViolation) {
}
bool LatchAnalyzer::allowExitOnViolation() {
- return _allowExitOnViolation.load() && (getTestCommandsEnabled());
+ return _allowExitOnViolation.load() && TestingProctor::instance().isEnabled();
}
LatchAnalyzer& LatchAnalyzer::get(ServiceContext* serviceContext) {
diff --git a/src/mongo/util/latch_analyzer_test.cpp b/src/mongo/util/latch_analyzer_test.cpp
index 9b4844d1311..8105925597a 100644
--- a/src/mongo/util/latch_analyzer_test.cpp
+++ b/src/mongo/util/latch_analyzer_test.cpp
@@ -41,17 +41,7 @@ namespace {
using Level = HierarchicalAcquisitionLevel;
-class LatchAnalyzerTest : public ServiceContextTest {
- void setUp() override {
- ServiceContextTest::setUp();
- setTestCommandsEnabled(true);
- }
-
- void tearDown() override {
- setTestCommandsEnabled(false);
- ServiceContextTest::tearDown();
- }
-};
+class LatchAnalyzerTest : public ServiceContextTest {};
DEATH_TEST_REGEX_F(LatchAnalyzerTest, AddInvalidWasAbsent, "Fatal assertion.*31360") {
diff --git a/src/mongo/util/testing_options.cpp b/src/mongo/util/testing_options.cpp
new file mode 100644
index 00000000000..8f886eedf9f
--- /dev/null
+++ b/src/mongo/util/testing_options.cpp
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2020-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.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
+
+#include "mongo/base/init.h"
+#include "mongo/logv2/log.h"
+#include "mongo/util/testing_options_gen.h"
+#include "mongo/util/testing_proctor.h"
+
+namespace mongo {
+namespace {
+
+/**
+ * The following initializer must always run before "DisableTestingDiagnosticsByDefault" to ensure
+ * it is allowed to set (enables/disables) testing diagnostics.
+ */
+MONGO_INITIALIZER_GENERAL(TestingDiagnostics,
+ ("EndServerParameterRegistration"),
+ ("DisableTestingDiagnosticsByDefault"))
+(InitializerContext*) {
+ // Initialize testing diagnostics only if it has not been already initialized, or it must be
+ // enabled by the initializer (i.e., "testingDiagnosticsEnabled=true"). This ensures testing
+ // diagnostics cannot be set beyond this point.
+ if (!TestingProctor::instance().isInitialized() || gTestingDiagnosticsEnabledAtStartup) {
+ TestingProctor::instance().setEnabled(gTestingDiagnosticsEnabledAtStartup);
+ }
+
+ if (TestingProctor::instance().isEnabled()) {
+ LOGV2_OPTIONS(4672602,
+ {logv2::LogTag::kStartupWarnings},
+ "Testing behaviors are enabled. This has serious implications for both "
+ "performance and security.");
+ }
+
+ return Status::OK();
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/util/testing_options.idl b/src/mongo/util/testing_options.idl
new file mode 100644
index 00000000000..dfb3e0c0d9f
--- /dev/null
+++ b/src/mongo/util/testing_options.idl
@@ -0,0 +1,38 @@
+# Copyright (C) 2020-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.
+#
+
+global:
+ cpp_namespace: "mongo"
+
+server_parameters:
+ testingDiagnosticsEnabled:
+ description: 'Start with test-only diagnostic behavior enabled'
+ set_at: startup
+ cpp_vartype: bool
+ cpp_varname: gTestingDiagnosticsEnabledAtStartup
+ default: false
diff --git a/src/mongo/util/testing_proctor.cpp b/src/mongo/util/testing_proctor.cpp
new file mode 100644
index 00000000000..f9f378fb687
--- /dev/null
+++ b/src/mongo/util/testing_proctor.cpp
@@ -0,0 +1,80 @@
+/**
+ * Copyright (C) 2020-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.
+ */
+
+#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kDefault
+
+#include "mongo/util/testing_proctor.h"
+
+#include "mongo/base/init.h"
+#include "mongo/logv2/log.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/static_immortal.h"
+
+namespace mongo {
+
+TestingProctor& TestingProctor::instance() {
+ static StaticImmortal<TestingProctor> proctor{};
+ return proctor.value();
+}
+
+bool TestingProctor::isEnabled() const {
+ uassert(ErrorCodes::NotYetInitialized,
+ "Cannot check whether testing diagnostics is enabled before it is initialized",
+ isInitialized());
+ return _diagnosticsEnabled.get();
+}
+
+void TestingProctor::setEnabled(bool enable) {
+ if (!isInitialized()) {
+ _diagnosticsEnabled = enable;
+ return;
+ }
+
+ uassert(ErrorCodes::AlreadyInitialized,
+ "Cannot alter testing diagnostics once initialized",
+ _diagnosticsEnabled.get() == enable);
+
+ LOGV2(4672601, "Overriding testing diagnostics", "enabled"_attr = enable);
+}
+
+namespace {
+
+/**
+ * The initializer ensures that testing diagnostics is always initialized (by default to disabled),
+ * especially for those executables that never call into `setEnabled()` (e.g., the mongo shell).
+ */
+MONGO_INITIALIZER(DisableTestingDiagnosticsByDefault)(InitializerContext*) {
+ if (!TestingProctor::instance().isInitialized()) {
+ TestingProctor::instance().setEnabled(false);
+ }
+ return Status::OK();
+}
+
+} // namespace
+} // namespace mongo
diff --git a/src/mongo/util/testing_proctor.h b/src/mongo/util/testing_proctor.h
new file mode 100644
index 00000000000..48a59cb0697
--- /dev/null
+++ b/src/mongo/util/testing_proctor.h
@@ -0,0 +1,67 @@
+/**
+ * Copyright (C) 2020-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.
+ */
+
+#pragma once
+
+#include <boost/optional.hpp>
+
+namespace mongo {
+
+/**
+ * Provides the apparatus to control the passive testing behavior and diagnostics. Testing
+ * diagnostics can be controlled via the "testingDiagnosticsEnabled" server parameter, or
+ * directly through calling "TestingProctor::instance().setEnabled()".
+ */
+class TestingProctor {
+public:
+ static TestingProctor& instance();
+
+ bool isInitialized() const noexcept {
+ return _diagnosticsEnabled.has_value();
+ }
+
+ /**
+ * Throws "ErrorCodes::NotYetInitialized" if called before any invocation of "setEnabled()" to
+ * initialize "_diagnosticsEnabled".
+ */
+ bool isEnabled() const;
+
+ /**
+ * Enables/disables testing diagnostics. Once invoked for the first time during the lifetime of
+ * a process, its impact (i.e., enabled or disabled diagnostics) cannot be altered. Throws
+ * "ErrorCodes::AlreadyInitialized" if the caller provides a value for "enable" that does not
+ * match what is stored in "_diagnosticsEnabled".
+ */
+ void setEnabled(bool enable);
+
+private:
+ boost::optional<bool> _diagnosticsEnabled;
+};
+
+} // namespace mongo