/**
* Copyright (C) 2012 10gen 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 .
*
* 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/client/connpool.h"
#include "mongo/client/dbclientinterface.h"
#include "mongo/client/dbclient_rs.h"
#include "mongo/client/replica_set_monitor.h"
#include "mongo/client/replica_set_monitor_internal.h"
#include "mongo/dbtests/mock/mock_conn_registry.h"
#include "mongo/dbtests/mock/mock_replica_set.h"
#include "mongo/unittest/unittest.h"
#include
#include
using std::map;
using std::vector;
using std::set;
using std::string;
using boost::scoped_ptr;
using mongo::BSONObj;
using mongo::BSONObjBuilder;
using mongo::BSONArray;
using mongo::BSONArrayBuilder;
using mongo::BSONElement;
using mongo::ConnectionString;
using mongo::HostAndPort;
using mongo::MockReplicaSet;
using mongo::ReadPreference;
using mongo::ReadPreferenceSetting;
using mongo::ReplicaSetMonitor;
using mongo::ReplicaSetMonitorPtr;
using mongo::ScopedDbConnection;
using mongo::TagSet;
// Pull nested types to top-level scope
typedef ReplicaSetMonitor::IsMasterReply IsMasterReply;
typedef ReplicaSetMonitor::ScanState ScanState;
typedef ReplicaSetMonitor::ScanStatePtr ScanStatePtr;
typedef ReplicaSetMonitor::SetState SetState;
typedef ReplicaSetMonitor::SetStatePtr SetStatePtr;
typedef ReplicaSetMonitor::Refresher Refresher;
typedef Refresher::NextStep NextStep;
typedef ScanState::UnconfirmedReplies UnconfirmedReplies;
typedef SetState::Node Node;
typedef SetState::Nodes Nodes;
namespace mongo_test {
bool isCompatible(const Node& node, ReadPreference pref, const TagSet& tagSet) {
set seeds;
seeds.insert(node.host);
SetState set("name", seeds);
set.nodes.push_back(node);
ReadPreferenceSetting criteria(pref, tagSet);
return !set.getMatchingHost(criteria).empty();
}
HostAndPort selectNode(const vector& nodes,
ReadPreference pref,
const TagSet& tagSet,
int latencyThresholdMillis,
bool* isPrimarySelected)
{
invariant(!nodes.empty());
set seeds;
seeds.insert(nodes.front().host);
SetState set("name", seeds);
set.nodes = nodes;
set.latencyThresholdMicros = latencyThresholdMillis * 1000;
ReadPreferenceSetting criteria(pref, tagSet);
HostAndPort out = set.getMatchingHost(criteria);
if (isPrimarySelected)
*isPrimarySelected = !out.empty() && set.findNode(out)->isMaster;
return out;
}
const BSONObj SampleIsMasterDoc = BSON("tags"
<< BSON("dc" << "NYC"
<< "p" << "2"
<< "region" << "NA"));
const BSONObj SampleTags = SampleIsMasterDoc["tags"].Obj();
const BSONObj NoTags = BSONObj();
const BSONObj NoTagIsMasterDoc = BSON("isMaster" << true);
TEST(ReplSetMonitorNode, SimpleGoodMatch) {
Node node(((HostAndPort())));
node.tags = BSON("dc" << "sf");
ASSERT(node.matches(BSON("dc" << "sf")));
}
TEST(ReplSetMonitorNode, SimpleBadMatch) {
Node node((HostAndPort()));
node.tags = BSON("dc" << "nyc");
ASSERT(!node.matches(BSON("dc" << "sf")));
}
TEST(ReplSetMonitorNode, ExactMatch) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(node.matches(SampleIsMasterDoc["tags"].Obj()));
}
TEST(ReplSetMonitorNode, EmptyTag) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(node.matches(BSONObj()));
}
TEST(ReplSetMonitorNode, MemberNoTagMatchesEmptyTag) {
Node node((HostAndPort()));
node.tags = NoTags;
ASSERT(node.matches(BSONObj()));
}
TEST(ReplSetMonitorNode, MemberNoTagDoesNotMatch) {
Node node((HostAndPort()));
node.tags = NoTags;
ASSERT(!node.matches(BSON("dc" << "NYC")));
}
TEST(ReplSetMonitorNode, IncompleteMatch) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(!node.matches(BSON("dc" << "NYC"
<< "p" << "2"
<< "hello" << "world")));
}
TEST(ReplSetMonitorNode, PartialMatch) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(node.matches(BSON("dc" << "NYC"
<< "p" << "2")));
}
TEST(ReplSetMonitorNode, SingleTagCrit) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(node.matches(BSON("p" << "2")));
}
TEST(ReplSetMonitorNode, BadSingleTagCrit) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(!node.matches(BSON("dc" << "SF")));
}
TEST(ReplSetMonitorNode, NonExistingFieldTag) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(!node.matches(BSON("noSQL" << "Mongo")));
}
TEST(ReplSetMonitorNode, UnorederedMatching) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(node.matches(BSON("p" << "2" << "dc" << "NYC")));
}
TEST(ReplSetMonitorNode, SameValueDiffKey) {
Node node((HostAndPort()));
node.tags = SampleTags;
ASSERT(!node.matches(BSON("datacenter" << "NYC")));
}
TEST(ReplSetMonitorNode, PriNodeCompatibleTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = true;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "NYC"));
TagSet tags(BSONArray(builder.done()));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, SecNodeCompatibleTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = false;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "NYC"));
TagSet tags(BSONArray(builder.done()));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, PriNodeNotCompatibleTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = true;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "SF"));
TagSet tags(BSONArray(builder.done()));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, SecNodeNotCompatibleTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = false;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "SF"));
TagSet tags(BSONArray(builder.done()));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, PriNodeCompatiblMultiTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = true;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "RP"));
builder.append(BSON("dc" << "NYC" << "p" << "2"));
TagSet tags(BSONArray(builder.done()));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, SecNodeCompatibleMultiTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = false;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "RP"));
builder.append(BSON("dc" << "NYC" << "p" << "2"));
TagSet tags(BSONArray(builder.done()));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, PriNodeNotCompatibleMultiTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = true;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "sf"));
builder.append(BSON("dc" << "NYC" << "P" << "4"));
TagSet tags(BSONArray(builder.done()));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
TEST(ReplSetMonitorNode, SecNodeNotCompatibleMultiTag) {
Node node(HostAndPort("dummy", 3));
node.tags = SampleTags;
node.isUp = true;
node.isMaster = false;
BSONArrayBuilder builder;
builder.append(BSON("dc" << "sf"));
builder.append(BSON("dc" << "NYC" << "P" << "4"));
TagSet tags(BSONArray(builder.done()));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_PrimaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryPreferred, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_SecondaryOnly, tags));
ASSERT(!isCompatible(node, mongo::ReadPreference_Nearest, tags));
}
class NodeSetFixtures {
public:
static vector getThreeMemberWithTags();
};
vector NodeSetFixtures::getThreeMemberWithTags() {
vector nodes;
nodes.push_back(Node(HostAndPort("a")));
nodes.push_back(Node(HostAndPort("b")));
nodes.push_back(Node(HostAndPort("c")));
nodes[0].isUp = true;
nodes[1].isUp = true;
nodes[2].isUp = true;
nodes[0].isMaster = false;
nodes[1].isMaster = true;
nodes[2].isMaster = false;
nodes[0].tags = BSON("dc" << "nyc" << "p" << "1");
nodes[1].tags = BSON("dc" << "sf");
nodes[2].tags = BSON("dc" << "nyc" << "p" << "2");
return nodes;
}
class TagSetFixtures {
public:
static BSONArray getDefaultSet();
static BSONArray getP2Tag();
static BSONArray getSingleNoMatchTag();
static BSONArray getMultiNoMatchTag();
};
BSONArray TagSetFixtures::getDefaultSet() {
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSONObj());
return arrayBuilder.arr();
}
BSONArray TagSetFixtures::getP2Tag() {
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "2"));
return arrayBuilder.arr();
}
BSONArray TagSetFixtures::getSingleNoMatchTag() {
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("k" << "x"));
return arrayBuilder.arr();
}
BSONArray TagSetFixtures::getMultiNoMatchTag() {
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("mongo" << "db"));
arrayBuilder.append(BSON("by" << "10gen"));
return arrayBuilder.arr();
}
TEST(ReplSetMonitorReadPref, PrimaryOnly) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, PrimaryOnlyPriNotOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, PrimaryMissing) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[1].isMaster = false;
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, PriPrefWithPriOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 1,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, PriPrefWithPriNotOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 1,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT(host.host() == "a" || host.host() == "c");
}
TEST(ReplSetMonitorReadPref, SecOnly) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, tags, 1,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(ReplSetMonitorReadPref, SecOnlyOnlyPriOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[0].markFailed();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, tags, 1,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, SecPref) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 1,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(ReplSetMonitorReadPref, SecPrefWithNoSecOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[0].markFailed();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 1,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, SecPrefWithNoNodeOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[0].markFailed();
nodes[1].markFailed();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 1,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, NearestAllLocal) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[0].latencyMicros = 1*1000;
nodes[1].latencyMicros = 2*1000;
nodes[2].latencyMicros = 3*1000;
bool isPrimarySelected = 0;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
// Any host is ok
ASSERT(!host.empty());
ASSERT_EQUALS(isPrimarySelected, host.host() == "b");
}
TEST(ReplSetMonitorReadPref, NearestOneLocal) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getDefaultSet());
nodes[0].latencyMicros = 10*1000;
nodes[1].latencyMicros = 20*1000;
nodes[2].latencyMicros = 30*1000;
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT_EQUALS("a", host.host());
ASSERT(!isPrimarySelected);
}
TEST(ReplSetMonitorReadPref, PriOnlyWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getP2Tag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
// Note: PrimaryOnly ignores tag
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, PriPrefPriNotOkWithTags) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getP2Tag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST(ReplSetMonitorReadPref, PriPrefPriOkWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, PriPrefPriNotOkWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, SecOnlyWithTags) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getP2Tag());
bool isPrimarySelected;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST(ReplSetMonitorReadPref, SecOnlyWithTagsMatchOnlyPri) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("dc" << "sf"));
TagSet tags(arrayBuilder.arr());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, SecPrefWithTags) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getP2Tag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST(ReplSetMonitorReadPref, SecPrefSecNotOkWithTags) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("dc" << "nyc"));
TagSet tags(arrayBuilder.arr());
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(ReplSetMonitorReadPref, SecPrefPriOkWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, SecPrefPriNotOkWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, SecPrefPriOkWithSecNotMatchTag) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, NearestWithTags) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "1"));
TagSet tags(arrayBuilder.arr());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(ReplSetMonitorReadPref, NearestWithTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getSingleNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, MultiPriOnlyTag) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(ReplSetMonitorReadPref, MultiPriOnlyPriNotOkTag) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(ReplSetMonitorReadPref, PriPrefPriOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "1"));
arrayBuilder.append(BSON("p" << "2"));
TagSet tags(arrayBuilder.arr());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
class MultiTags: public mongo::unittest::Test {
public:
vector getNodes() const {
return NodeSetFixtures::getThreeMemberWithTags();
}
const TagSet& getMatchesFirstTagSet() {
if (matchFirstTags.get() != NULL) {
return *matchFirstTags;
}
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "1"));
arrayBuilder.append(BSON("p" << "2"));
matchFirstTags.reset(new TagSet(arrayBuilder.arr()));
return *matchFirstTags;
}
const TagSet& getMatchesSecondTagSet() {
if (matchSecondTags.get() != NULL) {
return *matchSecondTags;
}
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "3"));
arrayBuilder.append(BSON("p" << "2"));
arrayBuilder.append(BSON("p" << "1"));
matchSecondTags.reset(new TagSet(arrayBuilder.arr()));
return *matchSecondTags;
}
const TagSet& getMatchesLastTagSet() {
if (matchLastTags.get() != NULL) {
return *matchLastTags;
}
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "12"));
arrayBuilder.append(BSON("p" << "23"));
arrayBuilder.append(BSON("p" << "19"));
arrayBuilder.append(BSON("p" << "34"));
arrayBuilder.append(BSON("p" << "1"));
matchLastTags.reset(new TagSet(arrayBuilder.arr()));
return *matchLastTags;
}
const TagSet& getMatchesPriTagSet() {
if (matchPriTags.get() != NULL) {
return *matchPriTags;
}
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("dc" << "sf"));
arrayBuilder.append(BSON("p" << "1"));
matchPriTags.reset(new TagSet(arrayBuilder.arr()));
return *matchPriTags;
}
private:
scoped_ptr matchFirstTags;
scoped_ptr matchSecondTags;
scoped_ptr matchLastTags;
scoped_ptr matchPriTags;
};
TEST_F(MultiTags, MultiTagsMatchesFirst) {
vector nodes = getNodes();
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, PriPrefPriNotOkMatchesFirstNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, PriPrefPriNotOkMatchesSecondTest) {
vector nodes = getNodes();
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, PriPrefPriNotOkMatchesSecondNotOkTest) {
vector nodes = getNodes();
nodes[1].markFailed();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, PriPrefPriNotOkMatchesLastTest) {
vector nodes = getNodes();
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, PriPrefPriNotOkMatchesLastNotOkTest) {
vector nodes = getNodes();
nodes[0].markFailed();
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(host.empty());
}
TEST(MultiTags, PriPrefPriOkNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(MultiTags, PriPrefPriNotOkNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_PrimaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST_F(MultiTags, SecOnlyMatchesFirstTest) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecOnlyMatchesFirstNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, SecOnlyMatchesSecond) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, SecOnlyMatchesSecondNotOk) {
vector nodes = getNodes();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecOnlyMatchesLast) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecOnlyMatchesLastNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(host.empty());
}
TEST_F(MultiTags, SecOnlyMultiTagsWithPriMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, getMatchesPriTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecOnlyMultiTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryOnly, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST_F(MultiTags, SecPrefMatchesFirst) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecPrefMatchesFirstNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, SecPrefMatchesSecond) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, SecPrefMatchesSecondNotOk) {
vector nodes = getNodes();
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesSecondTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecPrefMatchesLast) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, SecPrefMatchesLastNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesLastTagSet(),
3, &isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST_F(MultiTags, SecPrefMultiTagsWithPriMatch) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, getMatchesPriTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(MultiTags, SecPrefMultiTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(MultiTags, SecPrefMultiTagsNoMatchPriNotOk) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
nodes[1].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_SecondaryPreferred, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST_F(MultiTags, NearestMatchesFirst) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, getMatchesFirstTagSet(),
3, &isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST(MultiTags, NearestMatchesFirstNotOk) {
vector nodes = NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("p" << "1"));
arrayBuilder.append(BSON("dc" << "sf"));
TagSet tags(arrayBuilder.arr());
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST_F(MultiTags, NearestMatchesSecond) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, getMatchesSecondTagSet(), 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("c", host.host());
}
TEST_F(MultiTags, NearestMatchesSecondNotOk) {
vector nodes = NodeSetFixtures::getThreeMemberWithTags();
BSONArrayBuilder arrayBuilder;
arrayBuilder.append(BSON("z" << "2"));
arrayBuilder.append(BSON("p" << "2"));
arrayBuilder.append(BSON("dc" << "sf"));
TagSet tags(arrayBuilder.arr());
nodes[2].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST_F(MultiTags, NearestMatchesLast) {
vector nodes = getNodes();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, getMatchesLastTagSet(), 3,
&isPrimarySelected);
ASSERT(!isPrimarySelected);
ASSERT_EQUALS("a", host.host());
}
TEST_F(MultiTags, NeatestMatchesLastNotOk) {
vector nodes = getNodes();
nodes[0].markFailed();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, getMatchesLastTagSet(), 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST_F(MultiTags, NearestMultiTagsWithPriMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, getMatchesPriTagSet(), 3,
&isPrimarySelected);
ASSERT(isPrimarySelected);
ASSERT_EQUALS("b", host.host());
}
TEST(MultiTags, NearestMultiTagsNoMatch) {
vector nodes =
NodeSetFixtures::getThreeMemberWithTags();
TagSet tags(TagSetFixtures::getMultiNoMatchTag());
bool isPrimarySelected = false;
HostAndPort host = selectNode(nodes,
mongo::ReadPreference_Nearest, tags, 3,
&isPrimarySelected);
ASSERT(host.empty());
}
TEST(TagSet, DefaultConstructorMatchesAll) {
TagSet tags;
ASSERT_EQUALS(tags.getTagBSON(), BSON_ARRAY(BSONObj()));
}
// 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();
}
MockReplicaSet* getReplSet() {
return _replSet.get();
}
private:
ConnectionString::ConnectionHook* _originalConnectionHook;
boost::scoped_ptr _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 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();
}
// 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 seedList;
seedList.insert(HostAndPort(replSet.getPrimary()));
ReplicaSetMonitor::createIfNeeded(replSetName, seedList);
const MockReplicaSet::ReplConfigMap origConfig = replSet.getReplConfig();
mongo::ReplicaSetMonitorPtr replMonitor = ReplicaSetMonitor::get(replSetName);
for (size_t idxToRemove = 0; idxToRemove < NODE_COUNT; idxToRemove++) {
MockReplicaSet::ReplConfigMap newConfig = origConfig;
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();
newConfig.erase(hostToRemove);
replSet.setConfig(newConfig);
replSet.setPrimary(newConfig.begin()->first);
// Force refresh -> should not crash
replMonitor->startOrContinueRefresh().refreshAll();
}
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());
mongo::MockReplicaSet::ReplConfigMap config = _replSet->getReplConfig();
{
const string host(_replSet->getPrimary());
map& tag = config[host].tags;
tag.clear();
tag["dc"] = "ny";
tag["num"] = "1";
}
{
const string host(_replSet->getSecondaries().front());
map& tag = config[host].tags;
tag.clear();
tag["dc"] = "ny";
tag["num"] = "2";
}
_replSet->setConfig(config);
}
void tearDown() {
ConnectionString::setConnectionHook(_originalConnectionHook);
ReplicaSetMonitor::cleanup();
_replSet.reset();
}
MockReplicaSet* getReplSet() {
return _replSet.get();
}
private:
ConnectionString::ConnectionHook* _originalConnectionHook;
boost::scoped_ptr _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();
set seedList;
seedList.insert(HostAndPort(replSet->getPrimary()));
ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList);
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();
replSet->restore(secHost);
HostAndPort node = monitor->getHostOrRefresh(
ReadPreferenceSetting(mongo::ReadPreference_SecondaryOnly, TagSet()));
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();
set seedList;
seedList.insert(HostAndPort(replSet->getPrimary()));
ReplicaSetMonitor::createIfNeeded(replSet->getSetName(), seedList);
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();
replSet->restore(secHost);
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());
}
}