diff options
Diffstat (limited to 'src/mongo/executor')
5 files changed, 257 insertions, 124 deletions
diff --git a/src/mongo/executor/SConscript b/src/mongo/executor/SConscript index 7b2707464d2..de73d0ba464 100644 --- a/src/mongo/executor/SConscript +++ b/src/mongo/executor/SConscript @@ -200,20 +200,30 @@ env.CppUnitTest( '$BUILD_DIR/mongo/util/version_impl', ], ) - -env.CppIntegrationTest( - target='network_interface_asio_integration_test', +env.Library( + target='network_interface_asio_fixture', source=[ - 'network_interface_asio_integration_test.cpp', + 'network_interface_asio_integration_fixture.cpp' ], LIBDEPS=[ + 'network_interface_asio', + '$BUILD_DIR/mongo/unittest/integration_test_main', '$BUILD_DIR/mongo/executor/thread_pool_task_executor', '$BUILD_DIR/mongo/executor/network_interface_thread_pool', '$BUILD_DIR/mongo/executor/network_interface_factory', '$BUILD_DIR/mongo/rpc/command_status', '$BUILD_DIR/mongo/util/concurrency/thread_pool', '$BUILD_DIR/mongo/util/version_impl', - 'network_interface_asio', + ] +) + +env.CppIntegrationTest( + target='network_interface_asio_integration_test', + source=[ + 'network_interface_asio_integration_test.cpp', + ], + LIBDEPS=[ + 'network_interface_asio_fixture', ], ) diff --git a/src/mongo/executor/network_interface_asio_integration_fixture.cpp b/src/mongo/executor/network_interface_asio_integration_fixture.cpp new file mode 100644 index 00000000000..388de25f543 --- /dev/null +++ b/src/mongo/executor/network_interface_asio_integration_fixture.cpp @@ -0,0 +1,142 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kASIO + +#include "mongo/platform/basic.h" + +#include "mongo/client/connection_string.h" +#include "mongo/executor/async_stream_factory.h" +#include "mongo/executor/async_stream_interface.h" +#include "mongo/executor/async_timer_asio.h" +#include "mongo/executor/network_interface_asio.h" +#include "mongo/executor/network_interface_asio_integration_fixture.h" +#include "mongo/executor/remote_command_response.h" +#include "mongo/executor/task_executor.h" +#include "mongo/rpc/get_status_from_command_result.h" +#include "mongo/stdx/future.h" +#include "mongo/stdx/memory.h" +#include "mongo/unittest/integration_test.h" +#include "mongo/util/assert_util.h" +#include "mongo/util/log.h" + +namespace mongo { +namespace executor { +void NetworkInterfaceASIOIntegrationFixture::startNet(NetworkInterfaceASIO::Options options) { + options.streamFactory = stdx::make_unique<AsyncStreamFactory>(); + options.timerFactory = stdx::make_unique<AsyncTimerFactoryASIO>(); +#ifdef _WIN32 + // Connections won't queue on widnows, so attempting to open too many connections + // concurrently will result in refused connections and test failure. + options.connectionPoolOptions.maxConnections = 16u; +#else + options.connectionPoolOptions.maxConnections = 256u; +#endif + _net = stdx::make_unique<NetworkInterfaceASIO>(std::move(options)); + _net->startup(); +} + +void NetworkInterfaceASIOIntegrationFixture::tearDown() { + if (!_net->inShutdown()) { + _net->shutdown(); + } +} + +NetworkInterfaceASIO& NetworkInterfaceASIOIntegrationFixture::net() { + return *_net; +} + +ConnectionString NetworkInterfaceASIOIntegrationFixture::fixture() { + return unittest::getFixtureConnectionString(); +} + +void NetworkInterfaceASIOIntegrationFixture::setRandomNumberGenerator(PseudoRandom* generator) { + _rng = generator; +} + +PseudoRandom* NetworkInterfaceASIOIntegrationFixture::getRandomNumberGenerator() { + return _rng; +} + +void NetworkInterfaceASIOIntegrationFixture::startCommand( + const TaskExecutor::CallbackHandle& cbHandle, + RemoteCommandRequest& request, + StartCommandCB onFinish) { + net().startCommand(cbHandle, request, onFinish); +} + +Deferred<RemoteCommandResponse> NetworkInterfaceASIOIntegrationFixture::runCommand( + const TaskExecutor::CallbackHandle& cbHandle, RemoteCommandRequest& request) { + Deferred<RemoteCommandResponse> deferred; + net().startCommand(cbHandle, request, [deferred](RemoteCommandResponse resp) mutable { + deferred.emplace(std::move(resp)); + }); + return deferred; +} + +RemoteCommandResponse NetworkInterfaceASIOIntegrationFixture::runCommandSync( + RemoteCommandRequest& request) { + auto deferred = runCommand(makeCallbackHandle(), request); + auto& res = deferred.get(); + if (res.isOK()) { + log() << "got command result: " << res.toString(); + } else { + log() << "command failed: " << res.status; + } + return res; +} + +void NetworkInterfaceASIOIntegrationFixture::assertCommandOK(StringData db, + const BSONObj& cmd, + Milliseconds timeoutMillis) { + RemoteCommandRequest request{ + fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; + auto res = runCommandSync(request); + ASSERT_OK(res.status); + ASSERT_OK(getStatusFromCommandResult(res.data)); +} + +void NetworkInterfaceASIOIntegrationFixture::assertCommandFailsOnClient( + StringData db, const BSONObj& cmd, ErrorCodes::Error reason, Milliseconds timeoutMillis) { + RemoteCommandRequest request{ + fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; + auto res = runCommandSync(request); + ASSERT_EQ(reason, res.status.code()); +} + +void NetworkInterfaceASIOIntegrationFixture::assertCommandFailsOnServer( + StringData db, const BSONObj& cmd, ErrorCodes::Error reason, Milliseconds timeoutMillis) { + RemoteCommandRequest request{ + fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; + auto res = runCommandSync(request); + ASSERT_OK(res.status); + auto serverStatus = getStatusFromCommandResult(res.data); + ASSERT_EQ(reason, serverStatus); +} +} +} diff --git a/src/mongo/executor/network_interface_asio_integration_fixture.h b/src/mongo/executor/network_interface_asio_integration_fixture.h new file mode 100644 index 00000000000..3e62932b153 --- /dev/null +++ b/src/mongo/executor/network_interface_asio_integration_fixture.h @@ -0,0 +1,87 @@ +/** + * Copyright (C) 2017 MongoDB Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * 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 + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * 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 GNU Affero General 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/unittest/unittest.h" + +#include "mongo/executor/network_interface_asio.h" +#include "mongo/executor/network_interface_asio_test_utils.h" +#include "mongo/executor/task_executor.h" + +namespace mongo { + +class PseudoRandom; + +namespace executor { + +using StartCommandCB = stdx::function<void(const RemoteCommandResponse&)>; + +class NetworkInterfaceASIOIntegrationFixture : public mongo::unittest::Test { +public: + void startNet(NetworkInterfaceASIO::Options options = NetworkInterfaceASIO::Options()); + void tearDown() override; + + NetworkInterfaceASIO& net(); + + ConnectionString fixture(); + + void setRandomNumberGenerator(PseudoRandom* generator); + + PseudoRandom* getRandomNumberGenerator(); + + void startCommand(const TaskExecutor::CallbackHandle& cbHandle, + RemoteCommandRequest& request, + StartCommandCB onFinish); + + Deferred<RemoteCommandResponse> runCommand(const TaskExecutor::CallbackHandle& cbHandle, + RemoteCommandRequest& request); + + RemoteCommandResponse runCommandSync(RemoteCommandRequest& request); + + void assertCommandOK(StringData db, + const BSONObj& cmd, + Milliseconds timeoutMillis = Minutes(5)); + void assertCommandFailsOnClient(StringData db, + const BSONObj& cmd, + ErrorCodes::Error reason, + Milliseconds timeoutMillis = Minutes(5)); + + void assertCommandFailsOnServer(StringData db, + const BSONObj& cmd, + ErrorCodes::Error reason, + Milliseconds timeoutMillis = Minutes(5)); + +private: + std::unique_ptr<NetworkInterfaceASIO> _net; + PseudoRandom* _rng = nullptr; +}; + +} // namespace executor +} // namespace mongo diff --git a/src/mongo/executor/network_interface_asio_integration_test.cpp b/src/mongo/executor/network_interface_asio_integration_test.cpp index 654d5c60687..39282fb7fcd 100644 --- a/src/mongo/executor/network_interface_asio_integration_test.cpp +++ b/src/mongo/executor/network_interface_asio_integration_test.cpp @@ -34,12 +34,8 @@ #include <exception> #include "mongo/client/connection_string.h" -#include "mongo/executor/async_stream_factory.h" -#include "mongo/executor/async_stream_interface.h" -#include "mongo/executor/async_timer_asio.h" -#include "mongo/executor/network_interface_asio.h" +#include "mongo/executor/network_interface_asio_integration_fixture.h" #include "mongo/executor/network_interface_asio_test_utils.h" -#include "mongo/executor/task_executor.h" #include "mongo/platform/random.h" #include "mongo/rpc/get_status_from_command_result.h" #include "mongo/stdx/future.h" @@ -55,115 +51,12 @@ namespace mongo { namespace executor { namespace { -using StartCommandCB = stdx::function<void(const RemoteCommandResponse&)>; - -class NetworkInterfaceASIOIntegrationTest : public mongo::unittest::Test { -public: - void startNet(NetworkInterfaceASIO::Options options = NetworkInterfaceASIO::Options()) { - options.streamFactory = stdx::make_unique<AsyncStreamFactory>(); - options.timerFactory = stdx::make_unique<AsyncTimerFactoryASIO>(); -#ifdef _WIN32 - // Connections won't queue on windows, so attempting to open too many connections - // concurrently will result in refused connections and test failure. - options.connectionPoolOptions.maxConnections = 16u; -#else - options.connectionPoolOptions.maxConnections = 256u; -#endif - _net = stdx::make_unique<NetworkInterfaceASIO>(std::move(options)); - _net->startup(); - } - - void tearDown() override { - if (!_net->inShutdown()) { - _net->shutdown(); - } - } - - NetworkInterfaceASIO& net() { - return *_net; - } - - ConnectionString fixture() { - return unittest::getFixtureConnectionString(); - } - - void randomNumberGenerator(PseudoRandom* generator) { - _rng = generator; - } - - PseudoRandom* randomNumberGenerator() { - return _rng; - } - - void startCommand(const TaskExecutor::CallbackHandle& cbHandle, - RemoteCommandRequest& request, - StartCommandCB onFinish) { - net().startCommand(cbHandle, request, onFinish); - } - - Deferred<RemoteCommandResponse> runCommand(const TaskExecutor::CallbackHandle& cbHandle, - RemoteCommandRequest& request) { - Deferred<RemoteCommandResponse> deferred; - net().startCommand(cbHandle, request, [deferred](RemoteCommandResponse resp) mutable { - deferred.emplace(std::move(resp)); - }); - return deferred; - } - - RemoteCommandResponse runCommandSync(RemoteCommandRequest& request) { - auto deferred = runCommand(makeCallbackHandle(), request); - auto& res = deferred.get(); - if (res.isOK()) { - log() << "got command result: " << res.toString(); - } else { - log() << "command failed: " << res.status; - } - return res; - } - - void assertCommandOK(StringData db, - const BSONObj& cmd, - Milliseconds timeoutMillis = Milliseconds(-1)) { - RemoteCommandRequest request{ - fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; - auto res = runCommandSync(request); - ASSERT_OK(res.status); - ASSERT_OK(getStatusFromCommandResult(res.data)); - } - - void assertCommandFailsOnClient(StringData db, - const BSONObj& cmd, - Milliseconds timeoutMillis, - ErrorCodes::Error reason) { - RemoteCommandRequest request{ - fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; - auto res = runCommandSync(request); - ASSERT_EQ(reason, res.status.code()); - } - - void assertCommandFailsOnServer(StringData db, - const BSONObj& cmd, - Milliseconds timeoutMillis, - ErrorCodes::Error reason) { - RemoteCommandRequest request{ - fixture().getServers()[0], db.toString(), cmd, BSONObj(), nullptr, timeoutMillis}; - auto res = runCommandSync(request); - ASSERT_OK(res.status); - auto serverStatus = getStatusFromCommandResult(res.data); - ASSERT_EQ(reason, serverStatus); - } - -private: - std::unique_ptr<NetworkInterfaceASIO> _net; - PseudoRandom* _rng = nullptr; -}; - -TEST_F(NetworkInterfaceASIOIntegrationTest, Ping) { +TEST_F(NetworkInterfaceASIOIntegrationFixture, Ping) { startNet(); assertCommandOK("admin", BSON("ping" << 1)); } -TEST_F(NetworkInterfaceASIOIntegrationTest, Timeouts) { +TEST_F(NetworkInterfaceASIOIntegrationFixture, Timeouts) { startNet(); // This sleep command will take 10 seconds, so we should time out client side first given // our timeout of 100 milliseconds. @@ -172,8 +65,8 @@ TEST_F(NetworkInterfaceASIOIntegrationTest, Timeouts) { << "none" << "secs" << 10), - Milliseconds(100), - ErrorCodes::ExceededTimeLimit); + ErrorCodes::ExceededTimeLimit, + Milliseconds(100)); // Run a sleep command that should return before we hit the ASIO timeout. assertCommandOK("admin", @@ -186,7 +79,7 @@ TEST_F(NetworkInterfaceASIOIntegrationTest, Timeouts) { class StressTestOp { public: - using Fixture = NetworkInterfaceASIOIntegrationTest; + using Fixture = NetworkInterfaceASIOIntegrationFixture; using Pool = ThreadPoolInterface; void run(Fixture* fixture, @@ -203,8 +96,8 @@ public: fixture->startCommand(cb, request, onFinish); if (_cancel) { - invariant(fixture->randomNumberGenerator()); - sleepmillis(fixture->randomNumberGenerator()->nextInt32(10)); + invariant(fixture->getRandomNumberGenerator()); + sleepmillis(fixture->getRandomNumberGenerator()->nextInt32(10)); fixture->net().cancelCommand(cb); } } @@ -252,7 +145,7 @@ private: bool _cancel; }; -TEST_F(NetworkInterfaceASIOIntegrationTest, StressTest) { +TEST_F(NetworkInterfaceASIOIntegrationFixture, StressTest) { constexpr std::size_t numOps = 500; RemoteCommandResponse testResults[numOps]; ErrorCodes::Error expectedResults[numOps]; @@ -265,7 +158,7 @@ TEST_F(NetworkInterfaceASIOIntegrationTest, StressTest) { log() << "Random seed is " << seed; auto rng = PseudoRandom(seed); // TODO: read from command line - randomNumberGenerator(&rng); + setRandomNumberGenerator(&rng); log() << "Starting stress test..."; for (std::size_t i = 0; i < numOps; ++i) { @@ -329,13 +222,13 @@ class HangingHook : public executor::NetworkConnectionHook { // Test that we time out a command if the connection hook hangs. -TEST_F(NetworkInterfaceASIOIntegrationTest, HookHangs) { +TEST_F(NetworkInterfaceASIOIntegrationFixture, HookHangs) { NetworkInterfaceASIO::Options options; options.networkConnectionHook = stdx::make_unique<HangingHook>(); startNet(std::move(options)); assertCommandFailsOnClient( - "admin", BSON("ping" << 1), Seconds(1), ErrorCodes::ExceededTimeLimit); + "admin", BSON("ping" << 1), ErrorCodes::ExceededTimeLimit, Seconds(1)); } } // namespace diff --git a/src/mongo/executor/network_interface_asio_test_utils.h b/src/mongo/executor/network_interface_asio_test_utils.h index b65d7eaa11e..54424735b9b 100644 --- a/src/mongo/executor/network_interface_asio_test_utils.h +++ b/src/mongo/executor/network_interface_asio_test_utils.h @@ -25,6 +25,7 @@ * exception statement from all source files in the program, then also delete * it in the license file. */ +#pragma once #include <memory> |