/** * Copyright (C) 2015 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 . * * 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 #include #include "mongo/client/replica_set_monitor.h" #include "mongo/client/replica_set_monitor_internal.h" #include "mongo/stdx/memory.h" #include "mongo/unittest/unittest.h" namespace mongo { namespace { using std::set; using std::vector; // Pull nested types to top-level scope typedef ReplicaSetMonitor::SetState SetState; typedef SetState::Node Node; 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 && !out.empty()) { Node* node = set.findNode(out); ASSERT(node); *isPrimarySelected = node->isMaster; } return out; } vector 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; } BSONArray getDefaultTagSet() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSONObj()); return arrayBuilder.arr(); } BSONArray getP2TagSet() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "2")); return arrayBuilder.arr(); } BSONArray getSingleNoMatchTag() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("k" << "x")); return arrayBuilder.arr(); } BSONArray getMultiNoMatchTag() { BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("mongo" << "db")); arrayBuilder.append(BSON("by" << "10gen")); return arrayBuilder.arr(); } TEST(ReplSetMonitorReadPref, PrimaryOnly) { vector nodes = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, PrimaryMissing) { vector nodes = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryOnly, tags, 1, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecPref) { vector nodes = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryPreferred, tags, 1, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, NearestAllLocal) { vector nodes = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getDefaultTagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getP2TagSet()); 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 = getThreeMemberWithTags(); TagSet tags(getP2TagSet()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(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 = getThreeMemberWithTags(); TagSet tags(getSingleNoMatchTag()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecOnlyWithTags) { vector nodes = getThreeMemberWithTags(); TagSet tags(getP2TagSet()); bool isPrimarySelected; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryOnly, tags, 3, &isPrimarySelected); ASSERT(!isPrimarySelected); ASSERT_EQUALS("c", host.host()); } TEST(ReplSetMonitorReadPref, SecOnlyWithTagsMatchOnlyPri) { vector nodes = 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 = getThreeMemberWithTags(); TagSet tags(getP2TagSet()); 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 = getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("dc" << "nyc")); TagSet tags(arrayBuilder.arr()); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); TagSet tags(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 = getThreeMemberWithTags(); TagSet tags(getSingleNoMatchTag()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, SecPrefPriOkWithSecNotMatchTag) { vector nodes = getThreeMemberWithTags(); TagSet tags(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 = 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 = getThreeMemberWithTags(); TagSet tags(getSingleNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::Nearest, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, MultiPriOnlyTag) { vector nodes = getThreeMemberWithTags(); TagSet tags(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 = getThreeMemberWithTags(); TagSet tags(getMultiNoMatchTag()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::PrimaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(ReplSetMonitorReadPref, PriPrefPriOk) { vector nodes = 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: 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: std::unique_ptr matchFirstTags; std::unique_ptr matchSecondTags; std::unique_ptr matchLastTags; std::unique_ptr matchPriTags; }; TEST_F(MultiTags, MultiTagsMatchesFirst) { vector nodes = getThreeMemberWithTags(); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::PrimaryPreferred, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST(MultiTags, PriPrefPriOkNoMatch) { vector nodes = getThreeMemberWithTags(); TagSet tags(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 = getThreeMemberWithTags(); TagSet tags(getMultiNoMatchTag()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::PrimaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecOnlyMatchesFirstTest) { vector nodes = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference::SecondaryOnly, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecOnlyMultiTagsWithPriMatch) { vector nodes = 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 = getThreeMemberWithTags(); TagSet tags(getMultiNoMatchTag()); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryOnly, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, SecPrefMatchesFirst) { vector nodes = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[2].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); TagSet tags(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 = getThreeMemberWithTags(); TagSet tags(getMultiNoMatchTag()); nodes[1].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode(nodes, mongo::ReadPreference::SecondaryPreferred, tags, 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, NearestMatchesFirst) { vector nodes = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); BSONArrayBuilder arrayBuilder; arrayBuilder.append(BSON("p" << "1")); arrayBuilder.append(BSON("dc" << "sf")); TagSet tags(arrayBuilder.arr()); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = 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({ErrorCodes::InternalError, "Test error"}); 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 = getThreeMemberWithTags(); 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 = getThreeMemberWithTags(); nodes[0].markFailed({ErrorCodes::InternalError, "Test error"}); bool isPrimarySelected = false; HostAndPort host = selectNode( nodes, mongo::ReadPreference::Nearest, getMatchesLastTagSet(), 3, &isPrimarySelected); ASSERT(host.empty()); } TEST_F(MultiTags, NearestMultiTagsWithPriMatch) { vector nodes = 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 = getThreeMemberWithTags(); TagSet tags(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())); } } // namespace } // namespace mongo