diff options
Diffstat (limited to 'src/mongo/dbtests/replica_set_monitor_test.cpp')
-rw-r--r-- | src/mongo/dbtests/replica_set_monitor_test.cpp | 450 |
1 files changed, 225 insertions, 225 deletions
diff --git a/src/mongo/dbtests/replica_set_monitor_test.cpp b/src/mongo/dbtests/replica_set_monitor_test.cpp index 12b814f4ad2..188a85ce966 100644 --- a/src/mongo/dbtests/replica_set_monitor_test.cpp +++ b/src/mongo/dbtests/replica_set_monitor_test.cpp @@ -40,264 +40,264 @@ namespace { - using namespace mongo; - - using std::map; - using std::vector; - using std::set; - using std::string; - using std::unique_ptr; - - // TODO: Port these existing tests here: replmonitor_bad_seed.js, repl_monitor_refresh.js - - /** - * Warning: Tests running this fixture cannot be run in parallel with other tests - * that uses ConnectionString::setConnectionHook - */ - class ReplicaSetMonitorTest: public mongo::unittest::Test { - protected: - void setUp() { - _replSet.reset(new MockReplicaSet("test", 3)); - _originalConnectionHook = ConnectionString::getConnectionHook(); - ConnectionString::setConnectionHook( - mongo::MockConnRegistry::get()->getConnStrHook()); - } +using namespace mongo; + +using std::map; +using std::vector; +using std::set; +using std::string; +using std::unique_ptr; + +// TODO: Port these existing tests here: replmonitor_bad_seed.js, repl_monitor_refresh.js + +/** + * Warning: Tests running this fixture cannot be run in parallel with other tests + * that uses ConnectionString::setConnectionHook + */ +class ReplicaSetMonitorTest : public mongo::unittest::Test { +protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 3)); + _originalConnectionHook = ConnectionString::getConnectionHook(); + ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); + } + + void tearDown() { + ConnectionString::setConnectionHook(_originalConnectionHook); + ReplicaSetMonitor::cleanup(); + _replSet.reset(); + mongo::ScopedDbConnection::clearPool(); + } - void tearDown() { - ConnectionString::setConnectionHook(_originalConnectionHook); - ReplicaSetMonitor::cleanup(); - _replSet.reset(); - mongo::ScopedDbConnection::clearPool(); + MockReplicaSet* getReplSet() { + return _replSet.get(); + } + +private: + ConnectionString::ConnectionHook* _originalConnectionHook; + std::unique_ptr<MockReplicaSet> _replSet; +}; + +TEST_F(ReplicaSetMonitorTest, SeedWithPriOnlySecDown) { + // Test to make sure that the monitor doesn't crash when + // ConnectionString::connect returns NULL + MockReplicaSet* replSet = getReplSet(); + replSet->kill(replSet->getSecondaries()); + + // Create a monitor with primary as the only seed list and the two secondaries + // down so a NULL connection object will be stored for these secondaries in + // the _nodes vector. + const string replSetName(replSet->getSetName()); + set<HostAndPort> seedList; + seedList.insert(HostAndPort(replSet->getPrimary())); + ReplicaSetMonitor::createIfNeeded(replSetName, seedList); + + replSet->kill(replSet->getPrimary()); + + ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); + // Trigger calls to Node::getConnWithRefresh + monitor->startOrContinueRefresh().refreshAll(); +} + +namespace { +/** + * Takes a repl::ReplicaSetConfig and a node to remove and returns a new config with equivalent + * members minus the one specified to be removed. NOTE: Does not copy over properties of the + * members other than their id and host. + */ +repl::ReplicaSetConfig _getConfigWithMemberRemoved(const repl::ReplicaSetConfig& oldConfig, + const HostAndPort& toRemove) { + BSONObjBuilder newConfigBuilder; + newConfigBuilder.append("_id", oldConfig.getReplSetName()); + newConfigBuilder.append("version", oldConfig.getConfigVersion()); + + BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); + for (repl::ReplicaSetConfig::MemberIterator member = oldConfig.membersBegin(); + member != oldConfig.membersEnd(); + ++member) { + if (member->getHostAndPort() == toRemove) { + continue; } - MockReplicaSet* getReplSet() { - return _replSet.get(); + membersBuilder.append( + BSON("_id" << member->getId() << "host" << member->getHostAndPort().toString())); + } + + membersBuilder.done(); + repl::ReplicaSetConfig newConfig; + ASSERT_OK(newConfig.initialize(newConfigBuilder.obj())); + ASSERT_OK(newConfig.validate()); + return newConfig; +} +} // namespace + +// Stress test case for a node that is previously a primary being removed from the set. +// This test goes through configurations with different positions for the primary node +// in the host list returned from the isMaster command. The test here is to make sure +// that the ReplicaSetMonitor will not crash under these situations. +TEST(ReplicaSetMonitorTest, PrimaryRemovedFromSetStress) { + const size_t NODE_COUNT = 5; + MockReplicaSet replSet("test", NODE_COUNT); + ConnectionString::ConnectionHook* originalConnHook = ConnectionString::getConnectionHook(); + ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); + + const string replSetName(replSet.getSetName()); + set<HostAndPort> seedList; + seedList.insert(HostAndPort(replSet.getPrimary())); + ReplicaSetMonitor::createIfNeeded(replSetName, seedList); + + const repl::ReplicaSetConfig& origConfig = replSet.getReplConfig(); + mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName); + + for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) { + replSet.setConfig(origConfig); + // Make sure the monitor sees the change + replMonitor->startOrContinueRefresh().refreshAll(); + + string hostToRemove; + { + BSONObjBuilder monitorStateBuilder; + replMonitor->appendInfo(monitorStateBuilder); + BSONObj monitorState = monitorStateBuilder.done(); + + BSONElement hostsElem = monitorState["hosts"]; + BSONElement addrElem = hostsElem[mongo::str::stream() << idxToRemove]["addr"]; + hostToRemove = addrElem.String(); } - private: - ConnectionString::ConnectionHook* _originalConnectionHook; - std::unique_ptr<MockReplicaSet> _replSet; - }; - - TEST_F(ReplicaSetMonitorTest, SeedWithPriOnlySecDown) { - // Test to make sure that the monitor doesn't crash when - // ConnectionString::connect returns NULL - MockReplicaSet* replSet = getReplSet(); - replSet->kill(replSet->getSecondaries()); - - // Create a monitor with primary as the only seed list and the two secondaries - // down so a NULL connection object will be stored for these secondaries in - // the _nodes vector. - const string replSetName(replSet->getSetName()); - set<HostAndPort> seedList; - seedList.insert(HostAndPort(replSet->getPrimary())); - ReplicaSetMonitor::createIfNeeded(replSetName, seedList); - - replSet->kill(replSet->getPrimary()); - - ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); - // Trigger calls to Node::getConnWithRefresh - monitor->startOrContinueRefresh().refreshAll(); + replSet.setPrimary(hostToRemove); + // Make sure the monitor sees the new primary + replMonitor->startOrContinueRefresh().refreshAll(); + + repl::ReplicaSetConfig newConfig = + _getConfigWithMemberRemoved(origConfig, HostAndPort(hostToRemove)); + replSet.setConfig(newConfig); + replSet.setPrimary(newConfig.getMemberAt(0).getHostAndPort().toString()); + // Force refresh -> should not crash + replMonitor->startOrContinueRefresh().refreshAll(); } -namespace { - /** - * Takes a repl::ReplicaSetConfig and a node to remove and returns a new config with equivalent - * members minus the one specified to be removed. NOTE: Does not copy over properties of the - * members other than their id and host. - */ - repl::ReplicaSetConfig _getConfigWithMemberRemoved(const repl::ReplicaSetConfig& oldConfig, - const HostAndPort& toRemove) { - BSONObjBuilder newConfigBuilder; + ReplicaSetMonitor::cleanup(); + ConnectionString::setConnectionHook(originalConnHook); + mongo::ScopedDbConnection::clearPool(); +} + +/** + * Warning: Tests running this fixture cannot be run in parallel with other tests + * that use ConnectionString::setConnectionHook. + */ +class TwoNodeWithTags : public mongo::unittest::Test { +protected: + void setUp() { + _replSet.reset(new MockReplicaSet("test", 2)); + _originalConnectionHook = ConnectionString::getConnectionHook(); + ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); + + repl::ReplicaSetConfig oldConfig = _replSet->getReplConfig(); + + mongo::BSONObjBuilder newConfigBuilder; newConfigBuilder.append("_id", oldConfig.getReplSetName()); newConfigBuilder.append("version", oldConfig.getConfigVersion()); - BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); - for (repl::ReplicaSetConfig::MemberIterator member = oldConfig.membersBegin(); - member != oldConfig.membersEnd(); ++member) { - if (member->getHostAndPort() == toRemove) { - continue; - } + mongo::BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); + + { + const string host(_replSet->getPrimary()); + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append( + BSON("_id" << member->getId() << "host" << host << "tags" << BSON("dc" + << "ny" + << "num" + << "1"))); + } - membersBuilder.append(BSON("_id" << member->getId() << - "host" << member->getHostAndPort().toString())); + { + const string host(_replSet->getSecondaries().front()); + const mongo::repl::MemberConfig* member = + oldConfig.findMemberByHostAndPort(HostAndPort(host)); + membersBuilder.append( + BSON("_id" << member->getId() << "host" << host << "tags" << BSON("dc" + << "ny" + << "num" + << "2"))); } membersBuilder.done(); + repl::ReplicaSetConfig newConfig; - ASSERT_OK(newConfig.initialize(newConfigBuilder.obj())); - ASSERT_OK(newConfig.validate()); - return newConfig; + fassert(28572, newConfig.initialize(newConfigBuilder.done())); + fassert(28571, newConfig.validate()); + _replSet->setConfig(newConfig); } -} // namespace - - // Stress test case for a node that is previously a primary being removed from the set. - // This test goes through configurations with different positions for the primary node - // in the host list returned from the isMaster command. The test here is to make sure - // that the ReplicaSetMonitor will not crash under these situations. - TEST(ReplicaSetMonitorTest, PrimaryRemovedFromSetStress) { - const size_t NODE_COUNT = 5; - MockReplicaSet replSet("test", NODE_COUNT); - ConnectionString::ConnectionHook* originalConnHook = - ConnectionString::getConnectionHook(); - ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook()); - - const string replSetName(replSet.getSetName()); - set<HostAndPort> seedList; - seedList.insert(HostAndPort(replSet.getPrimary())); - ReplicaSetMonitor::createIfNeeded(replSetName, seedList); - - const repl::ReplicaSetConfig& origConfig = replSet.getReplConfig(); - mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName); - - for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) { - - replSet.setConfig(origConfig); - // Make sure the monitor sees the change - replMonitor->startOrContinueRefresh().refreshAll(); - - string hostToRemove; - { - BSONObjBuilder monitorStateBuilder; - replMonitor->appendInfo(monitorStateBuilder); - BSONObj monitorState = monitorStateBuilder.done(); - - BSONElement hostsElem = monitorState["hosts"]; - BSONElement addrElem = hostsElem[mongo::str::stream() << idxToRemove]["addr"]; - hostToRemove = addrElem.String(); - } - - replSet.setPrimary(hostToRemove); - // Make sure the monitor sees the new primary - replMonitor->startOrContinueRefresh().refreshAll(); - - repl::ReplicaSetConfig newConfig = - _getConfigWithMemberRemoved(origConfig, HostAndPort(hostToRemove)); - replSet.setConfig(newConfig); - replSet.setPrimary(newConfig.getMemberAt(0).getHostAndPort().toString()); - // Force refresh -> should not crash - replMonitor->startOrContinueRefresh().refreshAll(); - } + void tearDown() { + ConnectionString::setConnectionHook(_originalConnectionHook); ReplicaSetMonitor::cleanup(); - ConnectionString::setConnectionHook(originalConnHook); - mongo::ScopedDbConnection::clearPool(); + _replSet.reset(); } - /** - * Warning: Tests running this fixture cannot be run in parallel with other tests - * that use ConnectionString::setConnectionHook. - */ - class TwoNodeWithTags: public mongo::unittest::Test { - protected: - void setUp() { - _replSet.reset(new MockReplicaSet("test", 2)); - _originalConnectionHook = ConnectionString::getConnectionHook(); - ConnectionString::setConnectionHook( - mongo::MockConnRegistry::get()->getConnStrHook()); - - repl::ReplicaSetConfig oldConfig = _replSet->getReplConfig(); - - mongo::BSONObjBuilder newConfigBuilder; - newConfigBuilder.append("_id", oldConfig.getReplSetName()); - newConfigBuilder.append("version", oldConfig.getConfigVersion()); - - mongo::BSONArrayBuilder membersBuilder(newConfigBuilder.subarrayStart("members")); - - { - const string host(_replSet->getPrimary()); - const mongo::repl::MemberConfig* member = - oldConfig.findMemberByHostAndPort(HostAndPort(host)); - membersBuilder.append(BSON("_id" << member->getId() << - "host" << host << - "tags" << BSON("dc" << "ny" << - "num" << "1"))); - } - - { - const string host(_replSet->getSecondaries().front()); - const mongo::repl::MemberConfig* member = - oldConfig.findMemberByHostAndPort(HostAndPort(host)); - membersBuilder.append(BSON("_id" << member->getId() << - "host" << host << - "tags" << BSON("dc" << "ny" << - "num" << "2"))); - } - - membersBuilder.done(); - - repl::ReplicaSetConfig newConfig; - fassert(28572, newConfig.initialize(newConfigBuilder.done())); - fassert(28571, newConfig.validate()); - _replSet->setConfig(newConfig); - } - - void tearDown() { - ConnectionString::setConnectionHook(_originalConnectionHook); - ReplicaSetMonitor::cleanup(); - _replSet.reset(); - } + MockReplicaSet* getReplSet() { + return _replSet.get(); + } - MockReplicaSet* getReplSet() { - return _replSet.get(); - } +private: + ConnectionString::ConnectionHook* _originalConnectionHook; + std::unique_ptr<MockReplicaSet> _replSet; +}; - private: - ConnectionString::ConnectionHook* _originalConnectionHook; - std::unique_ptr<MockReplicaSet> _replSet; - }; +// Tests the case where the connection to secondary went bad and the replica set +// monitor needs to perform a refresh of it's local view then retry the node selection +// again after the refresh. +TEST_F(TwoNodeWithTags, SecDownRetryNoTag) { + MockReplicaSet* replSet = getReplSet(); - // Tests the case where the connection to secondary went bad and the replica set - // monitor needs to perform a refresh of it's local view then retry the node selection - // again after the refresh. - TEST_F(TwoNodeWithTags, SecDownRetryNoTag) { - MockReplicaSet* replSet = getReplSet(); + set<HostAndPort> seedList; + seedList.insert(HostAndPort(replSet->getPrimary())); + ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); - set<HostAndPort> seedList; - seedList.insert(HostAndPort(replSet->getPrimary())); - ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); + const string secHost(replSet->getSecondaries().front()); + replSet->kill(secHost); - const string secHost(replSet->getSecondaries().front()); - replSet->kill(secHost); + ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); + // Make sure monitor sees the dead secondary + monitor->startOrContinueRefresh().refreshAll(); - ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); - // Make sure monitor sees the dead secondary - monitor->startOrContinueRefresh().refreshAll(); + replSet->restore(secHost); - replSet->restore(secHost); + HostAndPort node = monitor->getHostOrRefresh( + ReadPreferenceSetting(mongo::ReadPreference::SecondaryOnly, TagSet())); - HostAndPort node = monitor->getHostOrRefresh( - ReadPreferenceSetting(mongo::ReadPreference::SecondaryOnly, TagSet())); + ASSERT_FALSE(monitor->isPrimary(node)); + ASSERT_EQUALS(secHost, node.toString()); +} - ASSERT_FALSE(monitor->isPrimary(node)); - ASSERT_EQUALS(secHost, node.toString()); - } +// Tests the case where the connection to secondary went bad and the replica set +// monitor needs to perform a refresh of it's local view then retry the node selection +// with tags again after the refresh. +TEST_F(TwoNodeWithTags, SecDownRetryWithTag) { + MockReplicaSet* replSet = getReplSet(); - // Tests the case where the connection to secondary went bad and the replica set - // monitor needs to perform a refresh of it's local view then retry the node selection - // with tags again after the refresh. - TEST_F(TwoNodeWithTags, SecDownRetryWithTag) { - MockReplicaSet* replSet = getReplSet(); + set<HostAndPort> seedList; + seedList.insert(HostAndPort(replSet->getPrimary())); + ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); - set<HostAndPort> seedList; - seedList.insert(HostAndPort(replSet->getPrimary())); - ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList); + const string secHost(replSet->getSecondaries().front()); + replSet->kill(secHost); - const string secHost(replSet->getSecondaries().front()); - replSet->kill(secHost); + ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); + // Make sure monitor sees the dead secondary + monitor->startOrContinueRefresh().refreshAll(); - ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName()); - // Make sure monitor sees the dead secondary - monitor->startOrContinueRefresh().refreshAll(); + replSet->restore(secHost); - replSet->restore(secHost); + TagSet tags(BSON_ARRAY(BSON("dc" + << "ny"))); + HostAndPort node = monitor->getHostOrRefresh( + ReadPreferenceSetting(mongo::ReadPreference::SecondaryOnly, tags)); - TagSet tags(BSON_ARRAY(BSON("dc" << "ny"))); - HostAndPort node = monitor->getHostOrRefresh( - ReadPreferenceSetting(mongo::ReadPreference::SecondaryOnly, tags)); - - ASSERT_FALSE(monitor->isPrimary(node)); - ASSERT_EQUALS(secHost, node.toString()); - } + ASSERT_FALSE(monitor->isPrimary(node)); + ASSERT_EQUALS(secHost, node.toString()); +} -} // namespace mongo +} // namespace mongo |