@@ -769,3 +769,185 @@ TEST(ReplicaSetMonitorTests, OutOfBandFailedHost) {
769769 }
770770 }
771771}
772+
773+ // Newly elected primary with electionId >= maximum electionId seen by the Refresher
774+ TEST (ReplicaSetMonitorTests, NewPrimaryWithMaxElectionId) {
775+ SetStatePtr state = boost::make_shared<SetState>(" name" , basicSeedsSet);
776+ Refresher refresher (state);
777+
778+ set<HostAndPort> seen;
779+
780+ // get all hosts to contact first
781+ for (size_t i = 0 ; i != basicSeeds.size (); ++i) {
782+ NextStep ns = refresher.getNextStep ();
783+ ASSERT_EQUALS (ns.step , NextStep::CONTACT_HOST);
784+ ASSERT (basicSeedsSet.count (ns.host ));
785+ ASSERT (!seen.count (ns.host ));
786+ seen.insert (ns.host );
787+ }
788+
789+ const ReadPreferenceSetting primaryOnly (ReadPreference_PrimaryOnly, TagSet ());
790+
791+ // mock all replies
792+ for (size_t i = 0 ; i != basicSeeds.size (); ++i) {
793+ // All hosts to talk to are already dispatched, but no reply has been received
794+ NextStep ns = refresher.getNextStep ();
795+ ASSERT_EQUALS (ns.step , NextStep::WAIT);
796+ ASSERT (ns.host .empty ());
797+
798+ refresher.receivedIsMaster (basicSeeds[i],
799+ -1 ,
800+ BSON (" setName" << " name"
801+ << " ismaster" << true
802+ << " secondary" << false
803+ << " hosts" << BSON_ARRAY (" a" << " b" << " c" )
804+ << " electionId" << OID::gen ()
805+ << " ok" << true ));
806+
807+ // Ensure the set primary is the host we just got a reply from
808+ HostAndPort currentPrimary = state->getMatchingHost (primaryOnly);
809+ ASSERT_EQUALS (currentPrimary.host (), basicSeeds[i].host ());
810+ ASSERT_EQUALS (state->nodes .size (), basicSeeds.size ());
811+
812+ // Check the state of each individual node
813+ for (size_t j = 0 ; j != basicSeeds.size (); ++j) {
814+ Node* node = state->findNode (basicSeeds[j]);
815+ ASSERT (node);
816+ ASSERT_EQUALS (node->host .toString (), basicSeeds[j].toString ());
817+ ASSERT_EQUALS (node->isUp , j <= i);
818+ ASSERT_EQUALS (node->isMaster , j == i);
819+ ASSERT (node->tags .isEmpty ());
820+ }
821+ }
822+
823+ // Now all hosts have returned data
824+ NextStep ns = refresher.getNextStep ();
825+ ASSERT_EQUALS (ns.step , NextStep::DONE);
826+ ASSERT (ns.host .empty ());
827+ }
828+
829+ // Ignore electionId of secondaries
830+ TEST (ReplicaSetMonitorTests, IgnoreElectionIdFromSecondaries) {
831+ SetStatePtr state = boost::make_shared<SetState>(" name" , basicSeedsSet);
832+ Refresher refresher (state);
833+
834+ set<HostAndPort> seen;
835+
836+ const OID primaryElectionId = OID::gen ();
837+
838+ // mock all replies
839+ for (size_t i = 0 ; i != basicSeeds.size (); ++i) {
840+ NextStep ns = refresher.getNextStep ();
841+ ASSERT_EQUALS (ns.step , NextStep::CONTACT_HOST);
842+ ASSERT (basicSeedsSet.count (ns.host ));
843+ ASSERT (!seen.count (ns.host ));
844+ seen.insert (ns.host );
845+
846+ // mock a reply
847+ const bool primary = ns.host .host () == " a" ;
848+ refresher.receivedIsMaster (ns.host ,
849+ -1 ,
850+ BSON (" setName" << " name"
851+ << " ismaster" << primary
852+ << " secondary" << !primary
853+ << " electionId" << (primary ?
854+ primaryElectionId : OID::gen ())
855+ << " hosts" << BSON_ARRAY (" a" << " b" << " c" )
856+ << " ok" << true ));
857+ }
858+
859+ // check that the SetState's maxElectionId == primary's electionId
860+ ASSERT_EQUALS (state->maxElectionId , primaryElectionId);
861+
862+ // Now all hosts have returned data
863+ NextStep ns = refresher.getNextStep ();
864+ ASSERT_EQUALS (ns.step , NextStep::DONE);
865+ ASSERT (ns.host .empty ());
866+ }
867+
868+ // Stale Primary with obsolete electionId
869+ TEST (ReplicaSetMonitorTests, StalePrimaryWithObsoleteElectionId) {
870+ SetStatePtr state = boost::make_shared<SetState>(" name" , basicSeedsSet);
871+ Refresher refresher (state);
872+
873+ const OID firstElectionId = OID::gen ();
874+ const OID secondElectionId = OID::gen ();
875+
876+ set<HostAndPort> seen;
877+
878+ // contact first host claiming to be primary with greater electionId
879+ {
880+ NextStep ns = refresher.getNextStep ();
881+ ASSERT_EQUALS (ns.step , NextStep::CONTACT_HOST);
882+ ASSERT (basicSeedsSet.count (ns.host ));
883+ ASSERT (!seen.count (ns.host ));
884+ seen.insert (ns.host );
885+
886+ refresher.receivedIsMaster (ns.host ,
887+ -1 ,
888+ BSON (" setName" << " name"
889+ << " ismaster" << true
890+ << " secondary" << false
891+ << " electionId" << secondElectionId
892+ << " hosts" << BSON_ARRAY (" a" << " b" << " c" )
893+ << " ok" << true ));
894+
895+ Node* node = state->findNode (ns.host );
896+ ASSERT (node);
897+ ASSERT_TRUE (node->isMaster );
898+ ASSERT_EQUALS (state->maxElectionId , secondElectionId);
899+ }
900+
901+ // contact second host claiming to be primary with smaller electionId
902+ {
903+ NextStep ns = refresher.getNextStep ();
904+ ASSERT_EQUALS (ns.step , NextStep::CONTACT_HOST);
905+ ASSERT (basicSeedsSet.count (ns.host ));
906+ ASSERT (!seen.count (ns.host ));
907+ seen.insert (ns.host );
908+
909+ refresher.receivedIsMaster (ns.host ,
910+ -1 ,
911+ BSON (" setName" << " name"
912+ << " ismaster" << true
913+ << " secondary" << false
914+ << " electionId" << firstElectionId
915+ << " hosts" << BSON_ARRAY (" a" << " b" << " c" )
916+ << " ok" << true ));
917+
918+ Node* node = state->findNode (ns.host );
919+ ASSERT (node);
920+ // The SetState shouldn't see this host as master
921+ ASSERT_FALSE (node->isMaster );
922+ // the max electionId should remain the same
923+ ASSERT_EQUALS (state->maxElectionId , secondElectionId);
924+ }
925+
926+ // third host is a secondary
927+ {
928+ NextStep ns = refresher.getNextStep ();
929+ ASSERT_EQUALS (ns.step , NextStep::CONTACT_HOST);
930+ ASSERT (basicSeedsSet.count (ns.host ));
931+ ASSERT (!seen.count (ns.host ));
932+ seen.insert (ns.host );
933+
934+ refresher.receivedIsMaster (ns.host ,
935+ -1 ,
936+ BSON (" setName" << " name"
937+ << " ismaster" << false
938+ << " secondary" << true
939+ << " hosts" << BSON_ARRAY (" a" << " b" << " c" )
940+ << " ok" << true ));
941+
942+ Node* node = state->findNode (ns.host );
943+ ASSERT (node);
944+ ASSERT_FALSE (node->isMaster );
945+ // the max electionId should remain the same
946+ ASSERT_EQUALS (state->maxElectionId , secondElectionId);
947+ }
948+
949+ // Now all hosts have returned data
950+ NextStep ns = refresher.getNextStep ();
951+ ASSERT_EQUALS (ns.step , NextStep::DONE);
952+ ASSERT (ns.host .empty ());
953+ }
0 commit comments