summaryrefslogtreecommitdiff
path: root/src/mongo/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/executor')
-rw-r--r--src/mongo/executor/SConscript8
-rw-r--r--src/mongo/executor/mock_network_fixture.cpp148
-rw-r--r--src/mongo/executor/mock_network_fixture.h237
-rw-r--r--src/mongo/executor/mock_network_fixture_test.cpp102
-rw-r--r--src/mongo/executor/network_interface_mock_test.cpp57
-rw-r--r--src/mongo/executor/network_interface_mock_test_fixture.cpp64
-rw-r--r--src/mongo/executor/network_interface_mock_test_fixture.h70
7 files changed, 629 insertions, 57 deletions
diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript
index 600547a89b7..2cb463484bd 100644
--- a/src/mongo/executor/SConscript
+++ b/src/mongo/executor/SConscript
@@ -85,6 +85,7 @@ env.Library(
env.Library(
target='network_interface_mock',
source=[
+ 'mock_network_fixture.cpp',
'network_interface_mock.cpp',
'thread_pool_mock.cpp',
],
@@ -95,7 +96,10 @@ env.Library(
'$BUILD_DIR/mongo/util/net/network',
'network_interface',
'task_executor_interface',
- ]
+ ],
+ LIBDEPS_PRIVATE=[
+ '$BUILD_DIR/mongo/db/matcher/expressions',
+ ],
)
env.Library(
@@ -281,7 +285,9 @@ env.CppUnitTest(
source=[
'connection_pool_test.cpp',
'connection_pool_test_fixture.cpp',
+ 'mock_network_fixture_test.cpp',
'network_interface_mock_test.cpp',
+ 'network_interface_mock_test_fixture.cpp',
'scoped_task_executor_test.cpp',
'task_executor_cursor_test.cpp',
'thread_pool_task_executor_test.cpp',
diff --git a/src/mongo/executor/mock_network_fixture.cpp b/src/mongo/executor/mock_network_fixture.cpp
new file mode 100644
index 00000000000..da028d8a6ba
--- /dev/null
+++ b/src/mongo/executor/mock_network_fixture.cpp
@@ -0,0 +1,148 @@
+/**
+ * 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::kTest
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/executor/mock_network_fixture.h"
+
+#include "mongo/db/matcher/matcher.h"
+#include "mongo/executor/network_interface_mock.h"
+#include "mongo/logv2/log.h"
+
+namespace mongo {
+namespace test {
+namespace mock {
+
+MockNetwork::Matcher::Matcher(const BSONObj& matcherQuery) {
+ auto expCtx = make_intrusive<ExpressionContext>(
+ nullptr /* opCtx */, nullptr /* collator */, NamespaceString{"db.coll"} /* dummy nss */);
+ // Expression matcher doesn't have copy constructor, so wrap it in a shared_ptr for capture.
+ auto m = std::make_shared<mongo::Matcher>(matcherQuery, std::move(expCtx));
+ _matcherFunc = [=](const BSONObj& request) { return m->matches(request); };
+}
+
+bool MockNetwork::_allExpectationsSatisfied() const {
+ return std::all_of(_expectations.begin(), _expectations.end(), [](const auto& exp) {
+ return exp->isDefault() || exp->isSatisfied();
+ });
+}
+
+void MockNetwork::_runUntilIdle() {
+ executor::NetworkInterfaceMock::InNetworkGuard guard(_net);
+ do {
+ // The main responsibility of the mock network is to host incoming requests and scheduled
+ // responses. Additionally, the mock network interface is a de facto lock-step scheduler.
+ //
+ // The executor thread and the mock/test thread run in turn. The test thread
+ // (1) triggers the tested behavior, e.g. by simulating a command;
+ // (2) responds to network requests;
+ // (3) advances the mock clock; and
+ // (4) handles some network operations implicitly (explained below).
+ // The executor runs the asynchronous jobs which may schedule network requests.
+ //
+ // The executor thread gets the first turn, then each of them yields at the end of their
+ // turns by enabling and signaling the other. The executor thread yields by calling
+ // waitForWork() on the mock network; the test thread yields by calling
+ // runReadyNetworkOperations().
+ //
+ // runReadyNetworkOperations() also first checks for expired scheduled works (e.g. request
+ // timeout) and executes the expired works. This behavior is the item (4) mentioned above.
+ //
+ // After yielding to the executor thread, it's possible that new expired scheduled works
+ // were added by the executor. That's why we need to double check if there's any ready
+ // network operations before deciding the network is idle.
+ //
+ // External threads may make things more complex. For example, they can schedule new
+ // requests right after we thought the network was idle. However, that's always the case
+ // with or without the mock framework.
+ _net->runReadyNetworkOperations();
+ if (_net->hasReadyRequests()) {
+ // Peek the next request.
+ auto noi = _net->getFrontOfUnscheduledQueue();
+ auto request = noi->getRequest().cmdObj;
+
+ // We ignore the next request if it's not expected (or already satisfied).
+ // Default expectations are always the oldest in the vector, so matching expectations
+ // in LIFO order allows us to always see the overrides first.
+ // (Iterating a vector backwards is much cheaper than pushing to its front.)
+ auto const& exp =
+ std::find_if(_expectations.rbegin(), _expectations.rend(), [&](const auto& exp) {
+ return !exp->isSatisfied() && exp->match(request);
+ });
+
+ if (exp != _expectations.rend()) {
+ // Consume the next request and execute the action.
+ noi = _net->getNextReadyRequest();
+ auto response = (*exp)->run(request);
+ LOGV2_DEBUG(5015401,
+ 1,
+ "mock reply ",
+ "request"_attr = request,
+ "response"_attr = response);
+ _net->scheduleResponse(noi, _net->now(), response);
+
+ // Continue handling network operations and process requests.
+ continue;
+ }
+ }
+
+ // The executor is idle since we just ran it. Check hasReadyNetworkOperations so that no
+ // scheduled work is waiting for the network thread.
+ } while (_net->hasReadyNetworkOperations());
+}
+
+void MockNetwork::runUntilExpectationsSatisfied() {
+ // If there exist extra threads beside the executor and the mock/test thread, when the
+ // network is idle, the extra threads may be running and will schedule new requests. As a
+ // result, the current best practice is to busy-loop to prepare for that.
+ while (!_allExpectationsSatisfied()) {
+ _runUntilIdle();
+ }
+}
+
+void MockNetwork::runUntil(Date_t target) {
+ while (_net->now() < target) {
+ LOGV2_DEBUG(
+ 5015402, 1, "mock advances time", "from"_attr = _net->now(), "to"_attr = target);
+ {
+ executor::NetworkInterfaceMock::InNetworkGuard guard(_net);
+ // Even if we cannot reach target time, we are still making progress in the loop.
+ _net->runUntil(target);
+ }
+ // Run until idle.
+ _runUntilIdle();
+ }
+ LOGV2_DEBUG(5015403, 1, "mock reached time", "target"_attr = target);
+}
+
+} // namespace mock
+} // namespace test
+} // namespace mongo
diff --git a/src/mongo/executor/mock_network_fixture.h b/src/mongo/executor/mock_network_fixture.h
new file mode 100644
index 00000000000..a2628042097
--- /dev/null
+++ b/src/mongo/executor/mock_network_fixture.h
@@ -0,0 +1,237 @@
+/**
+ * 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 <limits>
+
+#include "mongo/executor/network_interface_mock.h"
+#include "mongo/stdx/thread.h"
+
+namespace mongo {
+
+class BSONObj;
+using executor::RemoteCommandResponse;
+
+namespace test {
+namespace mock {
+
+// MockNetwork wraps the NetworkInterfaceMock to provide a declarative approach
+// to specify expected behaviors on the network and to hide the interaction with
+// the NetworkInterfaceMock.
+class MockNetwork {
+public:
+ using MatcherFunc = std::function<bool(const BSONObj&)>;
+ using ActionFunc = std::function<RemoteCommandResponse(const BSONObj&)>;
+
+ class Matcher {
+ public:
+ Matcher(const char* cmdName) : Matcher(std::string(cmdName)) {}
+ Matcher(const std::string& cmdName) {
+ _matcherFunc = [=](const BSONObj& request) {
+ return request.firstElementFieldNameStringData() == cmdName;
+ };
+ }
+
+ Matcher(const BSONObj& matcherQuery);
+
+ Matcher(MatcherFunc matcherFunc) : _matcherFunc(std::move(matcherFunc)) {}
+
+ bool operator()(const BSONObj& request) {
+ return _matcherFunc(request);
+ }
+
+ private:
+ MatcherFunc _matcherFunc;
+ };
+
+ class Action {
+ public:
+ Action(ActionFunc func) : _actionFunc(std::move(func)){};
+
+ Action(const BSONObj& response) {
+ _actionFunc = [=](const BSONObj& request) {
+ return RemoteCommandResponse(response, Milliseconds(0));
+ };
+ }
+
+ Action(const RemoteCommandResponse& commandResponse) {
+ _actionFunc = [=](const BSONObj& request) { return commandResponse; };
+ }
+
+ RemoteCommandResponse operator()(const BSONObj& request) {
+ return _actionFunc(request);
+ }
+
+ private:
+ ActionFunc _actionFunc;
+ };
+
+ class Expectation {
+ public:
+ Expectation(Matcher matcher, Action action)
+ : _matcher(std::move(matcher)), _action(std::move(action)) {}
+ virtual ~Expectation() {}
+
+ bool match(const BSONObj& request) {
+ return _matcher(request);
+ }
+
+ RemoteCommandResponse run(const BSONObj& request) {
+ if (!isDefault()) {
+ _allowedTimes--;
+ }
+ return _action(request);
+ }
+
+ virtual bool isDefault() const {
+ return _allowedTimes == std::numeric_limits<int>::max();
+ }
+
+ bool isSatisfied() const {
+ return _allowedTimes == 0;
+ }
+
+ // May throw.
+ virtual void checkSatisfied() {}
+
+ protected:
+ int _allowedTimes = std::numeric_limits<int>::max();
+
+ private:
+ Matcher _matcher;
+ Action _action;
+ };
+
+ class UserExpectation : public Expectation {
+ public:
+ UserExpectation(Matcher matcher, Action action) : Expectation(matcher, action) {
+ // Default value, may be overriden by calling times().
+ _allowedTimes = 1;
+ }
+
+ Expectation& times(int t) {
+ _allowedTimes = t;
+ return *this;
+ }
+
+ bool isDefault() const override {
+ return false;
+ }
+
+ void checkSatisfied() override {
+ uassert(5015501, "UserExpectation not satisfied", isSatisfied());
+ }
+ };
+
+ class DefaultExpectation : public Expectation {
+ public:
+ DefaultExpectation(Matcher matcher, Action action) : Expectation(matcher, action) {}
+
+ bool isDefault() const override {
+ return true;
+ }
+ };
+
+ explicit MockNetwork(executor::NetworkInterfaceMock* net) : _net(net) {}
+
+ // Accept anything that Matcher's and Action's constructors allow.
+ // Use expect() to mandate the exact calls each test expects. They must all be satisfied
+ // or the test fails.
+ template <typename MatcherType>
+ UserExpectation& expect(MatcherType&& matcher, Action action) {
+ auto exp = std::make_unique<UserExpectation>(Matcher(std::forward<MatcherType>(matcher)),
+ std::move(action));
+ auto& ref = *exp;
+ _expectations.emplace_back(std::move(exp));
+ return ref;
+ }
+
+ // Accept anything that Matcher's and Action's constructors allow.
+ // Use defaultExpect() to specify shared behavior in test fixtures. This is best for
+ // uninteresting calls common to a class of tests.
+ // For these reasons, you are not allowed to declare further default expecations after
+ // having already enqueued user expectations.
+ template <typename MatcherType>
+ DefaultExpectation& defaultExpect(MatcherType&& matcher, Action action) {
+ auto order = std::none_of(_expectations.begin(), _expectations.end(), [](const auto& exp) {
+ return !exp->isDefault();
+ });
+ uassert(
+ 5015502, "All default expectations must be declared before user expectations.", order);
+
+ auto exp = std::make_unique<DefaultExpectation>(Matcher(std::forward<MatcherType>(matcher)),
+ std::move(action));
+ auto& ref = *exp;
+ _expectations.emplace_back(std::move(exp));
+ return ref;
+ }
+
+ void verifyExpectations() {
+ for (auto& exp : _expectations) {
+ // This expectation will throw if it has not been met.
+ exp->checkSatisfied();
+ }
+ }
+
+ // Removes user expectations only.
+ void clearExpectations() {
+ _expectations.erase(std::remove_if(_expectations.begin(),
+ _expectations.end(),
+ [&](auto& exp) { return !exp->isDefault(); }),
+ _expectations.end());
+ }
+
+ // Carries over default expectations but clears user expectations. Checks that the latter
+ // have all been satisfied in the process.
+ void verifyAndClearExpectations() {
+ // May throw.
+ verifyExpectations();
+ clearExpectations();
+ }
+
+
+ // Advance time to the target. Run network operations and process requests along the way.
+ void runUntil(Date_t targetTime);
+
+ // Run until both the executor and the network are idle and all expectations are satisfied.
+ // Otherwise, it hangs forever.
+ void runUntilExpectationsSatisfied();
+
+private:
+ void _runUntilIdle();
+ bool _allExpectationsSatisfied() const;
+
+ std::vector<std::unique_ptr<Expectation>> _expectations;
+ executor::NetworkInterfaceMock* _net;
+};
+
+} // namespace mock
+} // namespace test
+} // namespace mongo
diff --git a/src/mongo/executor/mock_network_fixture_test.cpp b/src/mongo/executor/mock_network_fixture_test.cpp
new file mode 100644
index 00000000000..f97b4e7f6eb
--- /dev/null
+++ b/src/mongo/executor/mock_network_fixture_test.cpp
@@ -0,0 +1,102 @@
+/**
+ * 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::kTest
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/base/status.h"
+#include "mongo/executor/mock_network_fixture.h"
+#include "mongo/executor/network_interface.h"
+#include "mongo/executor/network_interface_mock.h"
+#include "mongo/executor/network_interface_mock_test_fixture.h"
+#include "mongo/executor/thread_pool_mock.h"
+#include "mongo/logv2/log.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace {
+
+using namespace executor;
+using namespace test::mock;
+
+class MockNetworkTest : public NetworkInterfaceMockTest {
+public:
+ MockNetworkTest() : NetworkInterfaceMockTest(), _mock(&NetworkInterfaceMockTest::net()){};
+
+ MockNetwork& mock() {
+ return _mock;
+ }
+
+ void setUp() override {
+ NetworkInterfaceMockTest::setUp();
+ NetworkInterfaceMockTest::startNetwork();
+ }
+
+ void tearDown() override {
+ NetworkInterfaceMockTest::tearDown();
+ // Will check for unsatisfied expectations.
+ mock().verifyAndClearExpectations();
+ }
+
+ void evaluateResponse(const RemoteCommandOnAnyResponse& resp, BSONObj expectedResponse) {
+ LOGV2(5015503, "Test got command response", "resp"_attr = resp);
+ ASSERT(resp.isOK());
+ ASSERT(SimpleBSONObjComparator::kInstance.evaluate(expectedResponse == resp.data));
+ }
+
+ std::string kExampleCmdName = "someCommandName";
+ RemoteCommandRequestOnAny kExampleRequest{
+ {testHost()}, "testDB", BSON(kExampleCmdName << 1), rpc::makeEmptyMetadata(), nullptr};
+ BSONObj kExampleResponse = BSON("some"
+ << "response");
+
+private:
+ MockNetwork _mock;
+};
+
+TEST_F(MockNetworkTest, MockFixtureBasicTest) {
+ mock().expect(kExampleCmdName, kExampleResponse);
+
+ RemoteCommandRequestOnAny request{kExampleRequest};
+ bool commandFinished = false;
+
+ TaskExecutor::CallbackHandle cb;
+ auto finishFn = [&](const RemoteCommandOnAnyResponse& resp) {
+ evaluateResponse(resp, kExampleResponse);
+ commandFinished = true;
+ };
+ ASSERT_OK(net().startCommand(cb, request, finishFn));
+
+ mock().runUntilExpectationsSatisfied();
+ ASSERT(commandFinished);
+}
+
+} // namespace
+} // namespace mongo \ No newline at end of file
diff --git a/src/mongo/executor/network_interface_mock_test.cpp b/src/mongo/executor/network_interface_mock_test.cpp
index d0575679cdd..c3f419a391f 100644
--- a/src/mongo/executor/network_interface_mock_test.cpp
+++ b/src/mongo/executor/network_interface_mock_test.cpp
@@ -36,68 +36,13 @@
#include "mongo/base/status.h"
#include "mongo/executor/network_connection_hook.h"
#include "mongo/executor/network_interface.h"
-#include "mongo/executor/network_interface_mock.h"
+#include "mongo/executor/network_interface_mock_test_fixture.h"
#include "mongo/executor/test_network_connection_hook.h"
-#include "mongo/executor/thread_pool_mock.h"
-#include "mongo/unittest/unittest.h"
namespace mongo {
namespace executor {
namespace {
-class NetworkInterfaceMockTest : public mongo::unittest::Test {
-public:
- NetworkInterfaceMockTest()
- : _net{}, _executor(&_net, 1, ThreadPoolMock::Options()), _tearDownCalled(false) {}
-
- NetworkInterfaceMock& net() {
- return _net;
- }
-
- ThreadPoolMock& executor() {
- return _executor;
- }
-
- HostAndPort testHost() {
- return {"localHost", 27017};
- }
-
- // intentionally not done in setUp as some methods need to be called prior to starting
- // the network.
- void startNetwork() {
- net().startup();
- executor().startup();
- }
-
- virtual void setUp() override {
- _tearDownCalled = false;
- }
-
- virtual void tearDown() override {
- // We're calling tearDown() manually in some tests so
- // we can check post-conditions.
- if (_tearDownCalled) {
- return;
- }
- _tearDownCalled = true;
-
- net().exitNetwork();
- executor().shutdown();
- // Wake up sleeping executor threads so they clean up.
- net().signalWorkAvailable();
- executor().join();
- net().shutdown();
- }
-
- RemoteCommandRequestOnAny kUnimportantRequest{
- {testHost()}, "testDB", BSON("test" << 1), rpc::makeEmptyMetadata(), nullptr};
-
-private:
- NetworkInterfaceMock _net;
- ThreadPoolMock _executor;
- bool _tearDownCalled;
-};
-
TEST_F(NetworkInterfaceMockTest, ConnectionHook) {
bool validateCalled = false;
bool hostCorrectForValidate = false;
diff --git a/src/mongo/executor/network_interface_mock_test_fixture.cpp b/src/mongo/executor/network_interface_mock_test_fixture.cpp
new file mode 100644
index 00000000000..0efae253dc8
--- /dev/null
+++ b/src/mongo/executor/network_interface_mock_test_fixture.cpp
@@ -0,0 +1,64 @@
+/**
+ * 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/executor/network_interface_mock_test_fixture.h"
+
+namespace mongo {
+namespace executor {
+
+// Intentionally not done in setUp in case there are methods that need to be called prior to
+// starting the network.
+void NetworkInterfaceMockTest::startNetwork() {
+ net().startup();
+ executor().startup();
+}
+
+void NetworkInterfaceMockTest::setUp() {
+ _tearDownCalled = false;
+}
+
+void NetworkInterfaceMockTest::tearDown() {
+ // We're calling tearDown() manually in some tests so
+ // we can check post-conditions.
+ if (_tearDownCalled) {
+ return;
+ }
+ _tearDownCalled = true;
+
+ net().exitNetwork();
+ executor().shutdown();
+ // Wake up sleeping executor threads so they clean up.
+ net().signalWorkAvailable();
+ executor().join();
+ net().shutdown();
+}
+} // namespace executor
+} // namespace mongo \ No newline at end of file
diff --git a/src/mongo/executor/network_interface_mock_test_fixture.h b/src/mongo/executor/network_interface_mock_test_fixture.h
new file mode 100644
index 00000000000..a19d2be80e4
--- /dev/null
+++ b/src/mongo/executor/network_interface_mock_test_fixture.h
@@ -0,0 +1,70 @@
+/**
+ * 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 "mongo/executor/network_interface_mock.h"
+#include "mongo/executor/thread_pool_mock.h"
+#include "mongo/unittest/unittest.h"
+
+namespace mongo {
+namespace executor {
+
+class NetworkInterfaceMockTest : public mongo::unittest::Test {
+public:
+ NetworkInterfaceMockTest()
+ : _net{}, _executor(&_net, 1, ThreadPoolMock::Options()), _tearDownCalled(false) {}
+
+ NetworkInterfaceMock& net() {
+ return _net;
+ }
+
+ ThreadPoolMock& executor() {
+ return _executor;
+ }
+
+ HostAndPort testHost() {
+ return {"localHost", 27017};
+ }
+
+ void startNetwork();
+ virtual void setUp() override;
+ virtual void tearDown() override;
+
+ RemoteCommandRequestOnAny kUnimportantRequest{
+ {testHost()}, "testDB", BSON("test" << 1), rpc::makeEmptyMetadata(), nullptr};
+
+private:
+ NetworkInterfaceMock _net;
+ ThreadPoolMock _executor;
+ bool _tearDownCalled;
+};
+
+} // namespace executor
+} // namespace mongo \ No newline at end of file