19
19
* ReplicaSetMonitor::selectNode and TagSet
22
#include "mongo/client/connpool.h"
23
#include "mongo/client/dbclientinterface.h"
24
24
#include "mongo/client/dbclient_rs.h"
25
#include "mongo/dbtests/mock/mock_conn_registry.h"
26
#include "mongo/dbtests/mock/mock_replica_set.h"
25
27
#include "mongo/unittest/unittest.h"
29
using boost::scoped_ptr;
32
using mongo::BSONArray;
33
using mongo::BSONArrayBuilder;
34
using mongo::ReplicaSetMonitor;
35
using mongo::HostAndPort;
36
using mongo::ReadPreference;
33
using boost::scoped_ptr;
36
using mongo::BSONObjBuilder;
37
using mongo::BSONArray;
38
using mongo::BSONArrayBuilder;
39
using mongo::BSONElement;
40
using mongo::ConnectionString;
41
using mongo::HostAndPort;
42
using mongo::MockReplicaSet;
43
using mongo::ReadPreference;
44
using mongo::ReplicaSetMonitor;
45
using mongo::ReplicaSetMonitorPtr;
46
using mongo::ScopedDbConnection;
49
namespace mongo_test {
39
50
const BSONObj SampleIsMasterDoc = BSON("tags"
40
51
<< BSON("dc" << "NYC"
1403
1414
ASSERT_EQUALS("b", lastHost.host());
1417
TEST(TagSet, CopyConstructor) {
1421
BSONArrayBuilder builder;
1422
builder.append(BSON("dc" << "nyc"));
1423
builder.append(BSON("priority" << "1"));
1424
TagSet original(builder.arr());
1428
copy = new TagSet(original);
1431
ASSERT_FALSE(copy->isExhausted());
1432
ASSERT(copy->getCurrentTag().equal(BSON("dc" << "nyc")));
1435
ASSERT_FALSE(copy->isExhausted());
1436
ASSERT(copy->getCurrentTag().equal(BSON("priority" << "1")));
1439
ASSERT(copy->isExhausted());
1406
1444
TEST(TagSet, NearestMultiTagsNoMatch) {
1407
1445
vector<ReplicaSetMonitor::Node> nodes =
1408
1446
NodeSetFixtures::getThreeMemberWithTags();
1475
1513
ASSERT_THROWS(tags.getCurrentTag(), mongo::AssertionException);
1517
// TODO: Port these existing tests here: replmonitor_bad_seed.js, repl_monitor_refresh.js
1520
* Warning: Tests running this fixture cannot be run in parallel with other tests
1521
* that uses ConnectionString::setConnectionHook
1523
class ReplicaSetMonitorTest: public mongo::unittest::Test {
1526
_replSet.reset(new MockReplicaSet("test", 3));
1527
_originalConnectionHook = ConnectionString::getConnectionHook();
1528
ConnectionString::setConnectionHook(
1529
mongo::MockConnRegistry::get()->getConnStrHook());
1533
ConnectionString::setConnectionHook(_originalConnectionHook);
1534
ReplicaSetMonitor::remove(_replSet->getSetName(), true);
1536
mongo::ScopedDbConnection::clearPool();
1539
MockReplicaSet* getReplSet() {
1540
return _replSet.get();
1544
ConnectionString::ConnectionHook* _originalConnectionHook;
1545
boost::scoped_ptr<MockReplicaSet> _replSet;
1548
TEST_F(ReplicaSetMonitorTest, SeedWithPriOnlySecDown) {
1549
// Test to make sure that the monitor doesn't crash when
1550
// ConnectionString::connect returns NULL
1551
MockReplicaSet* replSet = getReplSet();
1552
replSet->kill(replSet->getSecondaries());
1554
// Create a monitor with primary as the only seed list and the two secondaries
1555
// down so a NULL connection object will be stored for these secondaries in
1556
// the _nodes vector.
1557
const string replSetName(replSet->getSetName());
1558
vector<HostAndPort> seedList;
1559
seedList.push_back(HostAndPort(replSet->getPrimary()));
1560
ReplicaSetMonitor::createIfNeeded(replSetName, seedList);
1562
replSet->kill(replSet->getPrimary());
1564
ReplicaSetMonitorPtr monitor = ReplicaSetMonitor::get(replSet->getSetName());
1565
// Trigger calls to Node::getConnWithRefresh
1566
monitor->check(true);
1569
// Stress test case for a node that is previously a primary being removed from the set.
1570
// This test goes through configurations with different positions for the primary node
1571
// in the host list returned from the isMaster command. The test here is to make sure
1572
// that the ReplicaSetMonitor will not crash under these situations.
1573
TEST(ReplicaSetMonitorTest, PrimaryRemovedFromSetStress) {
1574
const size_t NODE_COUNT = 5;
1575
MockReplicaSet replSet("test", NODE_COUNT);
1576
ConnectionString::ConnectionHook* originalConnHook =
1577
ConnectionString::getConnectionHook();
1578
ConnectionString::setConnectionHook(mongo::MockConnRegistry::get()->getConnStrHook());
1580
const string replSetName(replSet.getSetName());
1581
vector<HostAndPort> seedList;
1582
seedList.push_back(HostAndPort(replSet.getPrimary()));
1583
ReplicaSetMonitor::createIfNeeded(replSetName, seedList);
1585
const MockReplicaSet::ReplConfigMap origConfig = replSet.getReplConfig();
1586
mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName);
1588
for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) {
1589
MockReplicaSet::ReplConfigMap newConfig = origConfig;
1591
replSet.setConfig(origConfig);
1592
replMonitor->check(true); // Make sure the monitor sees the change
1594
string hostToRemove;
1596
BSONObjBuilder monitorStateBuilder;
1597
replMonitor->appendInfo(monitorStateBuilder);
1598
BSONObj monitorState = monitorStateBuilder.done();
1600
BSONElement hostsElem = monitorState["hosts"];
1601
BSONElement addrElem = hostsElem[mongo::str::stream() << idxToRemove]["addr"];
1602
hostToRemove = addrElem.String();
1605
replSet.setPrimary(hostToRemove);
1606
replMonitor->check(true); // Make sure the monitor sees the new primary
1608
newConfig.erase(hostToRemove);
1609
replSet.setConfig(newConfig);
1610
replSet.setPrimary(newConfig.begin()->first);
1611
replMonitor->check(true); // Force refresh -> should not crash
1614
ReplicaSetMonitor::remove(replSet.getSetName(), true);
1615
ConnectionString::setConnectionHook(originalConnHook);
1616
mongo::ScopedDbConnection::clearPool();