summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenety Goh <benety@mongodb.com>2017-03-09 14:50:59 -0500
committerBenety Goh <benety@mongodb.com>2017-03-23 16:00:31 -0400
commitc1964e817459a575a64609229a473d57d08aa4d0 (patch)
tree83d079215cfc9010f99ef381e7a3c7d8b9b11db3
parent41d56f108e341c88fe26632084d6140ea75813c0 (diff)
downloadmongo-c1964e817459a575a64609229a473d57d08aa4d0.tar.gz
SERVER-28204 added RollbackTest fixture
-rw-r--r--src/mongo/db/repl/SConscript19
-rw-r--r--src/mongo/db/repl/rollback_test_fixture.cpp115
-rw-r--r--src/mongo/db/repl/rollback_test_fixture.h118
-rw-r--r--src/mongo/db/repl/rs_rollback_test.cpp58
-rw-r--r--src/mongo/db/service_context_d_test_fixture.cpp5
-rw-r--r--src/mongo/db/service_context_d_test_fixture.h12
-rw-r--r--src/mongo/executor/task_executor_test_fixture.cpp5
-rw-r--r--src/mongo/executor/task_executor_test_fixture.h11
-rw-r--r--src/mongo/executor/thread_pool_task_executor_test_fixture.cpp7
-rw-r--r--src/mongo/executor/thread_pool_task_executor_test_fixture.h16
10 files changed, 308 insertions, 58 deletions
diff --git a/src/mongo/db/repl/SConscript b/src/mongo/db/repl/SConscript
index 54ae8e436c0..8bf2a589003 100644
--- a/src/mongo/db/repl/SConscript
+++ b/src/mongo/db/repl/SConscript
@@ -300,6 +300,22 @@ env.Library(
],
)
+env.Library(
+ target='rollback_test_fixture',
+ source=[
+ 'rollback_test_fixture.cpp',
+ ],
+ LIBDEPS=[
+ 'optime',
+ 'repl_settings',
+ 'replmocks',
+ #'serveronly', # CYCLE
+ '$BUILD_DIR/mongo/db/service_context',
+ '$BUILD_DIR/mongo/db/service_context_d_test_fixture',
+ '$BUILD_DIR/mongo/executor/thread_pool_task_executor_test_fixture',
+ ],
+)
+
env.CppUnitTest(
target='rs_rollback_test',
source=[
@@ -308,9 +324,8 @@ env.CppUnitTest(
LIBDEPS=[
'oplog_interface_local',
'oplog_interface_mock',
- 'replmocks',
+ 'rollback_test_fixture',
'rs_rollback',
- '$BUILD_DIR/mongo/db/service_context_d_test_fixture',
],
)
diff --git a/src/mongo/db/repl/rollback_test_fixture.cpp b/src/mongo/db/repl/rollback_test_fixture.cpp
new file mode 100644
index 00000000000..764a84a281d
--- /dev/null
+++ b/src/mongo/db/repl/rollback_test_fixture.cpp
@@ -0,0 +1,115 @@
+/**
+ * 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.
+ */
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/repl/rollback_test_fixture.h"
+
+#include <string>
+
+#include "mongo/db/client.h"
+#include "mongo/db/repl/oplog.h"
+#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/db/repl/replication_coordinator_mock.h"
+
+namespace mongo {
+namespace repl {
+
+namespace {
+
+/**
+ * Creates ReplSettings for ReplicationCoordinatorRollbackMock.
+ */
+ReplSettings createReplSettings() {
+ ReplSettings settings;
+ settings.setOplogSizeBytes(5 * 1024 * 1024);
+ settings.setReplSetString("mySet/node1:12345");
+ return settings;
+}
+
+/**
+ * Creates ThreadPoolMock::Options that initializes a Client for every thread created in the pool.
+ */
+executor::ThreadPoolMock::Options createThreadPoolOptions() {
+ executor::ThreadPoolMock::Options options;
+ options.onCreateThread = []() { Client::initThread("RollbackTest"); };
+ return options;
+}
+
+} // namespace
+
+RollbackTest::RollbackTest() : _threadPoolExecutorTest(createThreadPoolOptions()) {}
+
+void RollbackTest::setUp() {
+ _serviceContextMongoDTest.setUp();
+ _threadPoolExecutorTest.setUp();
+ _opCtx = cc().makeOperationContext();
+ auto serviceContext = _serviceContextMongoDTest.getServiceContext();
+ _coordinator = new ReplicationCoordinatorRollbackMock(serviceContext);
+ ReplicationCoordinator::set(serviceContext,
+ std::unique_ptr<ReplicationCoordinator>(_coordinator));
+ setOplogCollectionName();
+ _storageInterface.setAppliedThrough(_opCtx.get(), OpTime{});
+ _storageInterface.setMinValid(_opCtx.get(), OpTime{});
+
+ _threadPoolExecutorTest.launchExecutorThread();
+}
+
+void RollbackTest::tearDown() {
+ _coordinator = nullptr;
+ _opCtx.reset();
+ _threadPoolExecutorTest.tearDown();
+
+ // We cannot unset the global replication coordinator because ServiceContextMongoD::tearDown()
+ // calls dropAllDatabasesExceptLocal() which requires the replication coordinator to clear all
+ // snapshots.
+ _serviceContextMongoDTest.tearDown();
+
+ // ServiceContextMongoD::tearDown() does not destroy service context so it is okay
+ // to access the service context after tearDown().
+ auto serviceContext = _serviceContextMongoDTest.getServiceContext();
+ ReplicationCoordinator::set(serviceContext, {});
+}
+
+RollbackTest::ReplicationCoordinatorRollbackMock::ReplicationCoordinatorRollbackMock(
+ ServiceContext* service)
+ : ReplicationCoordinatorMock(service, createReplSettings()) {}
+
+void RollbackTest::ReplicationCoordinatorRollbackMock::resetLastOpTimesFromOplog(
+ OperationContext* opCtx) {}
+
+bool RollbackTest::ReplicationCoordinatorRollbackMock::setFollowerMode(
+ const MemberState& newState) {
+ if (newState == _failSetFollowerModeOnThisMemberState) {
+ return false;
+ }
+ return ReplicationCoordinatorMock::setFollowerMode(newState);
+}
+
+} // namespace repl
+} // namespace mongo
diff --git a/src/mongo/db/repl/rollback_test_fixture.h b/src/mongo/db/repl/rollback_test_fixture.h
new file mode 100644
index 00000000000..ece8cd682d2
--- /dev/null
+++ b/src/mongo/db/repl/rollback_test_fixture.h
@@ -0,0 +1,118 @@
+/**
+ * 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/db/repl/replication_coordinator_mock.h"
+#include "mongo/db/repl/storage_interface_mock.h"
+#include "mongo/db/service_context.h"
+#include "mongo/db/service_context_d_test_fixture.h"
+#include "mongo/executor/thread_pool_task_executor_test_fixture.h"
+
+namespace mongo {
+namespace repl {
+
+/**
+ * Test fixture for both 3.4 and 3.6 rollback unit tests.
+ * The fixture makes available to tests:
+ * - an "ephemeralForTest" storage engine for checking results of the rollback algorithm at the
+ * storage layer. The storage engine is initialized as part of the ServiceContextForMongoD test
+ * fixture.
+ * - a task executor for simulating remote command responses from the sync source. The
+ * ThreadPoolExecutorTest is used to initialize the task executor.
+ */
+class RollbackTest : public unittest::Test {
+public:
+ /**
+ * Initializes executor::ThreadPoolExecutorTest so that each thread is initialized with a
+ * Client.
+ */
+ RollbackTest();
+
+ /**
+ * Initializes the service context and task executor.
+ */
+ void setUp() override;
+
+ /**
+ * Destroys the service context and task executor.
+ *
+ * Note on overriding tearDown() in tests:
+ * Tests should explicitly shut down and join the task executor (by invoking
+ * TaskExecutorTest::shutdownExecutorThread() and TaskExecutorTest::joinExecutorThread()
+ * respectively) before calling RollbackTest::tearDown().
+ * This cancels outstanding tasks and remote command requests scheduled using the task
+ * executor.
+ */
+ void tearDown() override;
+
+protected:
+ // Test fixture used to manage the service context and global storage engine.
+ ServiceContextMongoDTest _serviceContextMongoDTest;
+
+ // Test fixture used to manage the task executor.
+ executor::ThreadPoolExecutorTest _threadPoolExecutorTest;
+
+ // OperationContext provided to test cases for storage layer operations.
+ ServiceContext::UniqueOperationContext _opCtx;
+
+ // ReplicationCoordinator mock implementation for rollback tests.
+ // Owned by service context.
+ class ReplicationCoordinatorRollbackMock;
+ ReplicationCoordinatorRollbackMock* _coordinator = nullptr;
+
+ // StorageInterface used to access minValid.
+ StorageInterfaceMock _storageInterface;
+};
+
+/**
+ * ReplicationCoordinator mock implementation for rollback tests.
+ */
+class RollbackTest::ReplicationCoordinatorRollbackMock : public ReplicationCoordinatorMock {
+public:
+ ReplicationCoordinatorRollbackMock(ServiceContext* service);
+
+ /**
+ * Base class implementation triggers an invariant. This function is overridden to be a no-op
+ * for rollback tests.
+ */
+ void resetLastOpTimesFromOplog(OperationContext* opCtx) override;
+
+ /**
+ * Returns false (does not forward call to ReplicationCoordinatorMock::setFollowerMode())
+ * if new state requested is '_failSetFollowerModeOnThisMemberState'.
+ * Otherwise, calls ReplicationCoordinatorMock::setFollowerMode().
+ */
+ bool setFollowerMode(const MemberState& newState) override;
+
+ // Override this to make setFollowerMode() fail when called with this state.
+ MemberState _failSetFollowerModeOnThisMemberState = MemberState::RS_UNKNOWN;
+};
+
+} // namespace repl
+} // namespace mongo
diff --git a/src/mongo/db/repl/rs_rollback_test.cpp b/src/mongo/db/repl/rs_rollback_test.cpp
index 90843d9a445..81e50bc27be 100644
--- a/src/mongo/db/repl/rs_rollback_test.cpp
+++ b/src/mongo/db/repl/rs_rollback_test.cpp
@@ -30,12 +30,10 @@
#include "mongo/platform/basic.h"
-#include <list>
+#include <initializer_list>
#include <utility>
#include "mongo/db/catalog/collection.h"
-#include "mongo/db/catalog/database.h"
-#include "mongo/db/catalog/database_holder.h"
#include "mongo/db/catalog/drop_indexes.h"
#include "mongo/db/catalog/index_catalog.h"
#include "mongo/db/catalog/index_create.h"
@@ -49,14 +47,10 @@
#include "mongo/db/repl/oplog.h"
#include "mongo/db/repl/oplog_interface.h"
#include "mongo/db/repl/oplog_interface_mock.h"
-#include "mongo/db/repl/replication_coordinator_global.h"
-#include "mongo/db/repl/replication_coordinator_mock.h"
#include "mongo/db/repl/rollback_source.h"
+#include "mongo/db/repl/rollback_test_fixture.h"
#include "mongo/db/repl/rs_rollback.h"
-#include "mongo/db/repl/storage_interface.h"
-#include "mongo/db/repl/storage_interface_mock.h"
#include "mongo/db/s/shard_identity_rollback_notifier.h"
-#include "mongo/db/service_context_d_test_fixture.h"
#include "mongo/stdx/memory.h"
#include "mongo/unittest/death_test.h"
#include "mongo/unittest/unittest.h"
@@ -71,28 +65,6 @@ const auto kIndexVersion = IndexDescriptor::IndexVersion::kV2;
const OplogInterfaceMock::Operations kEmptyMockOperations;
-ReplSettings createReplSettings() {
- ReplSettings settings;
- settings.setOplogSizeBytes(5 * 1024 * 1024);
- settings.setReplSetString("mySet/node1:12345");
- return settings;
-}
-
-class ReplicationCoordinatorRollbackMock : public ReplicationCoordinatorMock {
-public:
- ReplicationCoordinatorRollbackMock(ServiceContext* service)
- : ReplicationCoordinatorMock(service, createReplSettings()) {}
- void resetLastOpTimesFromOplog(OperationContext* opCtx) override {}
- bool setFollowerMode(const MemberState& newState) override {
- if (newState == _failSetFollowerModeOnThisMemberState) {
- return false;
- }
- return ReplicationCoordinatorMock::setFollowerMode(newState);
- }
- MemberState _failSetFollowerModeOnThisMemberState = MemberState::RS_UNKNOWN;
-};
-
-
class RollbackSourceMock : public RollbackSource {
public:
RollbackSourceMock(std::unique_ptr<OplogInterface> oplog);
@@ -137,38 +109,18 @@ StatusWith<BSONObj> RollbackSourceMock::getCollectionInfo(const NamespaceString&
return BSON("name" << nss.ns() << "options" << BSONObj());
}
-class RSRollbackTest : public ServiceContextMongoDTest {
-protected:
- ServiceContext::UniqueOperationContext _opCtx;
-
- // Owned by service context
- ReplicationCoordinatorRollbackMock* _coordinator;
-
- repl::StorageInterfaceMock _storageInterface;
-
+class RSRollbackTest : public RollbackTest {
private:
void setUp() override;
void tearDown() override;
};
void RSRollbackTest::setUp() {
- ServiceContextMongoDTest::setUp();
- _opCtx = cc().makeOperationContext();
- _coordinator = new ReplicationCoordinatorRollbackMock(_opCtx->getServiceContext());
-
- auto serviceContext = getServiceContext();
- ReplicationCoordinator::set(serviceContext,
- std::unique_ptr<ReplicationCoordinator>(_coordinator));
-
- setOplogCollectionName();
- _storageInterface.setAppliedThrough(_opCtx.get(), OpTime{});
- _storageInterface.setMinValid(_opCtx.get(), OpTime{});
+ RollbackTest::setUp();
}
void RSRollbackTest::tearDown() {
- _opCtx.reset();
- ServiceContextMongoDTest::tearDown();
- setGlobalReplicationCoordinator(nullptr);
+ RollbackTest::tearDown();
}
OplogInterfaceMock::Operation makeNoopOplogEntryAndRecordId(Seconds seconds) {
diff --git a/src/mongo/db/service_context_d_test_fixture.cpp b/src/mongo/db/service_context_d_test_fixture.cpp
index efa54fdd1a4..be62c952d22 100644
--- a/src/mongo/db/service_context_d_test_fixture.cpp
+++ b/src/mongo/db/service_context_d_test_fixture.cpp
@@ -46,6 +46,7 @@
#include "mongo/db/time_proof_service.h"
#include "mongo/stdx/memory.h"
#include "mongo/unittest/temp_dir.h"
+#include "mongo/util/assert_util.h"
#include "mongo/util/scopeguard.h"
namespace mongo {
@@ -84,6 +85,10 @@ ServiceContext* ServiceContextMongoDTest::getServiceContext() {
return getGlobalServiceContext();
}
+void ServiceContextMongoDTest::_doTest() {
+ MONGO_UNREACHABLE;
+}
+
void ServiceContextMongoDTest::_dropAllDBs(OperationContext* opCtx) {
dropAllDatabasesExceptLocal(opCtx);
diff --git a/src/mongo/db/service_context_d_test_fixture.h b/src/mongo/db/service_context_d_test_fixture.h
index 2442a10132a..402a1837724 100644
--- a/src/mongo/db/service_context_d_test_fixture.h
+++ b/src/mongo/db/service_context_d_test_fixture.h
@@ -39,7 +39,7 @@ class OperationContext;
* Test fixture class for tests that use either the "ephemeralForTest" or "devnull" storage engines.
*/
class ServiceContextMongoDTest : public unittest::Test {
-protected:
+public:
/**
* Initializes global storage engine.
*/
@@ -58,6 +58,16 @@ protected:
private:
/**
+ * Unused implementation of test function. This allows us to instantiate
+ * ServiceContextMongoDTest on its own without the need to inherit from it in a test.
+ * This supports using ServiceContextMongoDTest inside another test fixture and works around the
+ * limitation that tests cannot inherit from multiple test fixtures.
+ *
+ * It is an error to call this implementation of _doTest() directly.
+ */
+ void _doTest() override;
+
+ /**
* Drops all databases. Call this before global ReplicationCoordinator is destroyed -- it is
* used to drop the databases.
*/
diff --git a/src/mongo/executor/task_executor_test_fixture.cpp b/src/mongo/executor/task_executor_test_fixture.cpp
index bc99e1538fa..a97c3559e7e 100644
--- a/src/mongo/executor/task_executor_test_fixture.cpp
+++ b/src/mongo/executor/task_executor_test_fixture.cpp
@@ -34,6 +34,7 @@
#include "mongo/executor/network_interface_mock.h"
#include "mongo/executor/remote_command_request.h"
#include "mongo/stdx/memory.h"
+#include "mongo/util/assert_util.h"
#include "mongo/util/mongoutils/str.h"
namespace mongo {
@@ -100,6 +101,10 @@ void TaskExecutorTest::joinExecutorThread() {
_executorState = LifecycleState::kShutdownComplete;
}
+void TaskExecutorTest::_doTest() {
+ MONGO_UNREACHABLE;
+}
+
void TaskExecutorTest::postExecutorThreadLaunch() {}
} // namespace executor
diff --git a/src/mongo/executor/task_executor_test_fixture.h b/src/mongo/executor/task_executor_test_fixture.h
index d89b6e0062d..e90cbaec413 100644
--- a/src/mongo/executor/task_executor_test_fixture.h
+++ b/src/mongo/executor/task_executor_test_fixture.h
@@ -59,7 +59,6 @@ public:
static RemoteCommandRequest assertRemoteCommandNameEquals(StringData cmdName,
const RemoteCommandRequest& request);
-protected:
virtual ~TaskExecutorTest();
executor::NetworkInterfaceMock* getNet() {
@@ -86,6 +85,16 @@ protected:
void joinExecutorThread();
private:
+ /**
+ * Unused implementation of test function. This allows us to instantiate
+ * TaskExecutorTest on its own without the need to inherit from it in a test.
+ * This supports using TaskExecutorTest inside another test fixture and works around the
+ * limitation that tests cannot inherit from multiple test fixtures.
+ *
+ * It is an error to call this implementation of _doTest() directly.
+ */
+ void _doTest() override;
+
virtual std::unique_ptr<TaskExecutor> makeTaskExecutor(
std::unique_ptr<NetworkInterfaceMock> net) = 0;
diff --git a/src/mongo/executor/thread_pool_task_executor_test_fixture.cpp b/src/mongo/executor/thread_pool_task_executor_test_fixture.cpp
index 4973363707d..ebd0ea6dbbe 100644
--- a/src/mongo/executor/thread_pool_task_executor_test_fixture.cpp
+++ b/src/mongo/executor/thread_pool_task_executor_test_fixture.cpp
@@ -43,8 +43,13 @@ std::unique_ptr<ThreadPoolTaskExecutor> makeThreadPoolTestExecutor(
stdx::make_unique<ThreadPoolMock>(netPtr, 1, std::move(options)), std::move(net));
}
+ThreadPoolExecutorTest::ThreadPoolExecutorTest() {}
+
+ThreadPoolExecutorTest::ThreadPoolExecutorTest(ThreadPoolMock::Options options)
+ : _options(std::move(options)) {}
+
ThreadPoolMock::Options ThreadPoolExecutorTest::makeThreadPoolMockOptions() const {
- return ThreadPoolMock::Options();
+ return _options;
}
std::unique_ptr<TaskExecutor> ThreadPoolExecutorTest::makeTaskExecutor(
diff --git a/src/mongo/executor/thread_pool_task_executor_test_fixture.h b/src/mongo/executor/thread_pool_task_executor_test_fixture.h
index 31444809758..ebe2d77d23f 100644
--- a/src/mongo/executor/thread_pool_task_executor_test_fixture.h
+++ b/src/mongo/executor/thread_pool_task_executor_test_fixture.h
@@ -49,10 +49,26 @@ std::unique_ptr<ThreadPoolTaskExecutor> makeThreadPoolTestExecutor(
* Useful fixture class for tests that use a ThreadPoolTaskExecutor.
*/
class ThreadPoolExecutorTest : public TaskExecutorTest {
+public:
+ /**
+ * This default constructor supports the use of this class as a base class for a test fixture.
+ */
+ ThreadPoolExecutorTest();
+
+ /**
+ * This constructor supports the use of this class as a member variable to be used alongside
+ * another test fixture. Accepts a ThreadPoolMock::Options that will be used to override the
+ * result of makeThreadPoolMockOptions().
+ */
+ explicit ThreadPoolExecutorTest(ThreadPoolMock::Options options);
+
private:
virtual ThreadPoolMock::Options makeThreadPoolMockOptions() const;
std::unique_ptr<TaskExecutor> makeTaskExecutor(
std::unique_ptr<NetworkInterfaceMock> net) override;
+
+ // Returned by makeThreadPoolMockOptions().
+ const ThreadPoolMock::Options _options = {};
};
} // namespace executor