/** * Copyright (C) 2014 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 "mongo/unittest/unittest.h" #include "mongo/util/assert_util.h" #include "mongo/db/repl/repl_set_heartbeat_response.h" namespace mongo { namespace repl { namespace { using boost::scoped_ptr; using std::auto_ptr; bool stringContains(const std::string &haystack, const std::string& needle) { return haystack.find(needle) != std::string::npos; } TEST(ReplSetHeartbeatResponse, DefaultConstructThenSlowlyBuildToFullObj) { int fieldsSet = 2; ReplSetHeartbeatResponse hbResponse; ReplSetHeartbeatResponse hbResponseObjRoundTripChecker; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(false, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(false, hbResponse.hasTime()); ASSERT_EQUALS(false, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(-1, hbResponse.getVersion()); BSONObj hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); Status initializeResult = Status::OK(); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set version hbResponse.setVersion(1); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(false, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(false, hbResponse.hasTime()); ASSERT_EQUALS(false, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set setname hbResponse.setSetName("rs0"); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(false, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(false, hbResponse.hasTime()); ASSERT_EQUALS(false, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set electionTime hbResponse.setElectionTime(OpTime(10,0)); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(false, hbResponse.hasTime()); ASSERT_EQUALS(false, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set opTime hbResponse.setOpTime(Date_t(10)); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(false, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set time hbResponse.setTime(Seconds(10)); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(false, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set electable hbResponse.setElectable(true); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(false, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set config ReplicaSetConfig config; hbResponse.setConfig(config); ++fieldsSet; ASSERT_EQUALS(false, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set state hbResponse.setState(MemberState(MemberState::RS_SECONDARY)); ++fieldsSet; ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(false, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); ASSERT_EQUALS(2, hbResponseObj["state"].numberLong()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set stateDisagreement hbResponse.noteStateDisagreement(); ++fieldsSet; ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(false, hbResponse.isReplSet()); ASSERT_EQUALS(true, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); ASSERT_EQUALS(2, hbResponseObj["state"].numberLong()); ASSERT_EQUALS(false, hbResponseObj["mismatch"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["stateDisagreement"].trueValue()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set replSet hbResponse.noteReplSet(); ++fieldsSet; ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(true, hbResponse.isReplSet()); ASSERT_EQUALS(true, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); ASSERT_EQUALS(2, hbResponseObj["state"].numberLong()); ASSERT_EQUALS(false, hbResponseObj["mismatch"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["stateDisagreement"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["rs"].trueValue()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set syncingTo hbResponse.setSyncingTo("syncTarget"); ++fieldsSet; ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(true, hbResponse.isReplSet()); ASSERT_EQUALS(true, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("", hbResponse.getHbMsg()); ASSERT_EQUALS("syncTarget", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); ASSERT_EQUALS(2, hbResponseObj["state"].numberLong()); ASSERT_EQUALS(false, hbResponseObj["mismatch"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["stateDisagreement"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["rs"].trueValue()); ASSERT_EQUALS("syncTarget", hbResponseObj["syncingTo"].String()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set hbmsg hbResponse.setHbMsg("lub dub"); ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(false, hbResponse.isMismatched()); ASSERT_EQUALS(true, hbResponse.isReplSet()); ASSERT_EQUALS(true, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("lub dub", hbResponse.getHbMsg()); ASSERT_EQUALS("syncTarget", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(fieldsSet, hbResponseObj.nFields()); ASSERT_EQUALS("rs0", hbResponseObj["set"].String()); ASSERT_EQUALS("lub dub", hbResponseObj["hbmsg"].String()); ASSERT_EQUALS(1, hbResponseObj["v"].Number()); ASSERT_EQUALS(OpTime(10,0), hbResponseObj["electionTime"]._opTime()); ASSERT_EQUALS(OpTime(0,10), hbResponseObj["opTime"]._opTime()); ASSERT_EQUALS(10, hbResponseObj["time"].numberLong()); ASSERT_EQUALS(true, hbResponseObj["e"].trueValue()); ASSERT_EQUALS(config.toBSON().toString(), hbResponseObj["config"].Obj().toString()); ASSERT_EQUALS(2, hbResponseObj["state"].numberLong()); ASSERT_EQUALS(false, hbResponseObj["mismatch"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["stateDisagreement"].trueValue()); ASSERT_EQUALS(true, hbResponseObj["rs"].trueValue()); ASSERT_EQUALS("syncTarget", hbResponseObj["syncingTo"].String()); initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(hbResponseObj.toString(), hbResponseObjRoundTripChecker.toBSON().toString()); // set mismatched hbResponse.noteMismatched(); ASSERT_EQUALS(true, hbResponse.hasState()); ASSERT_EQUALS(true, hbResponse.hasElectionTime()); ASSERT_EQUALS(true, hbResponse.hasIsElectable()); ASSERT_EQUALS(true, hbResponse.hasTime()); ASSERT_EQUALS(true, hbResponse.hasOpTime()); ASSERT_EQUALS(true, hbResponse.hasConfig()); ASSERT_EQUALS(true, hbResponse.isMismatched()); ASSERT_EQUALS(true, hbResponse.isReplSet()); ASSERT_EQUALS(true, hbResponse.isStateDisagreement()); ASSERT_EQUALS("rs0", hbResponse.getReplicaSetName()); ASSERT_EQUALS(MemberState(MemberState::RS_SECONDARY).toString(), hbResponse.getState().toString()); ASSERT_EQUALS("lub dub", hbResponse.getHbMsg()); ASSERT_EQUALS("syncTarget", hbResponse.getSyncingTo()); ASSERT_EQUALS(1, hbResponse.getVersion()); ASSERT_EQUALS(OpTime(10,0), hbResponse.getElectionTime()); ASSERT_EQUALS(OpTime(0,10), hbResponse.getOpTime()); ASSERT_EQUALS(10, hbResponse.getTime().total_seconds()); ASSERT_EQUALS(true, hbResponse.isElectable()); ASSERT_EQUALS(config.toBSON().toString(), hbResponse.getConfig().toBSON().toString()); hbResponseObj = hbResponse.toBSON(); ASSERT_EQUALS(2, hbResponseObj.nFields()); ASSERT_EQUALS(true, hbResponseObj["mismatch"].trueValue()); // NOTE: Does not check round-trip. Once noteMismached is set the bson will return an error // from initialize parsing. initializeResult = hbResponseObjRoundTripChecker.initialize(hbResponseObj); ASSERT_NOT_EQUALS(Status::OK(), initializeResult); ASSERT_EQUALS(ErrorCodes::InconsistentReplicaSetNames, initializeResult.code()); } TEST(ReplSetHeartbeatResponse, InitializeWrongElectionTimeType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "electionTime" << "hello"); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"electionTime\" field in response to replSetHeartbeat command to " "have type Date or Timestamp, but found type String", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeWrongTimeType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "time" << "hello"); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"time\" field in response to replSetHeartbeat command to " "have a numeric type, but found type String", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeWrongOpTimeType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "opTime" << "hello"); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"opTime\" field in response to replSetHeartbeat command to " "have type Date or Timestamp, but found type String", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeMemberStateWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "state" << "hello"); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"state\" field in response to replSetHeartbeat command to " "have type NumberInt or NumberLong, but found type String", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeMemberStateTooLow) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "state" << -1); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::BadValue, result); ASSERT_EQUALS("Value for \"state\" in response to replSetHeartbeat is out of range; " "legal values are non-negative and no more than 10", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeMemberStateTooHigh) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "state" << 11); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::BadValue, result); ASSERT_EQUALS("Value for \"state\" in response to replSetHeartbeat is out of range; " "legal values are non-negative and no more than 10", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeVersionWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << "hello"); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"v\" field in response to replSetHeartbeat to " "have type NumberInt, but found String", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeReplSetNameWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << 2 << // needs a version to get this far in initialize() "set" << 4); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"set\" field in response to replSetHeartbeat to " "have type String, but found NumberInt32", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeHeartbeatMeessageWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << 2 << // needs a version to get this far in initialize() "hbmsg" << 4); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"hbmsg\" field in response to replSetHeartbeat to " "have type String, but found NumberInt32", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeSyncingToWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << 2 << // needs a version to get this far in initialize() "syncingTo" << 4); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"syncingTo\" field in response to replSetHeartbeat to " "have type String, but found NumberInt32", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeConfigWrongType) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << 2 << // needs a version to get this far in initialize() "config" << 4); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::TypeMismatch, result); ASSERT_EQUALS("Expected \"config\" in response to replSetHeartbeat to " "have type Object, but found NumberInt32", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeBadConfig) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 1.0 << "v" << 2 << // needs a version to get this far in initialize() "config" << BSON("illegalFieldName" << 2)); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::BadValue, result); ASSERT_EQUALS("Unexpected field illegalFieldName in replica set configuration", result.reason()); } TEST(ReplSetHeartbeatResponse, InitializeBothElectionTimeTypesSameResult) { ReplSetHeartbeatResponse hbResponseDate; ReplSetHeartbeatResponse hbResponseTimestamp; BSONObjBuilder initializerDate; BSONObjBuilder initializerTimestamp; Date_t electionTime = Date_t(974132); initializerDate.append("ok", 1.0); initializerDate.append("v", 1); initializerDate.appendDate("electionTime", electionTime); Status result = hbResponseDate.initialize(initializerDate.obj()); ASSERT_EQUALS(Status::OK(), result); initializerTimestamp.append("ok", 1.0); initializerTimestamp.append("v", 1); initializerTimestamp.appendTimestamp("electionTime", electionTime); result = hbResponseTimestamp.initialize(initializerTimestamp.obj()); ASSERT_EQUALS(Status::OK(), result); ASSERT_EQUALS(hbResponseTimestamp.getElectionTime(), hbResponseTimestamp.getElectionTime()); } TEST(ReplSetHeartbeatResponse, InitializeBothOpTimeTypesSameResult) { ReplSetHeartbeatResponse hbResponseDate; ReplSetHeartbeatResponse hbResponseTimestamp; BSONObjBuilder initializerDate; BSONObjBuilder initializerTimestamp; Date_t opTime = Date_t(974132); initializerDate.append("ok", 1.0); initializerDate.append("v", 1); initializerDate.appendDate("opTime", opTime); Status result = hbResponseDate.initialize(initializerDate.obj()); ASSERT_EQUALS(Status::OK(), result); initializerTimestamp.append("ok", 1.0); initializerTimestamp.append("v", 1); initializerTimestamp.appendTimestamp("opTime", opTime); result = hbResponseTimestamp.initialize(initializerTimestamp.obj()); ASSERT_EQUALS(Status::OK(), result); ASSERT_EQUALS(hbResponseTimestamp.getOpTime(), hbResponseTimestamp.getOpTime()); } TEST(ReplSetHeartbeatResponse, NoConfigStillInitializing) { ReplSetHeartbeatResponse hbResp; std::string msg = "still initializing"; Status result = hbResp.initialize(BSON("ok" << 1.0 << "rs" << true << "hbmsg" << msg)); ASSERT_EQUALS(Status::OK(), result); ASSERT_EQUALS(true, hbResp.isReplSet()); ASSERT_EQUALS(msg, hbResp.getHbMsg()); } TEST(ReplSetHeartbeatResponse, InvalidResponseOpTimeMissesConfigVersion) { ReplSetHeartbeatResponse hbResp; std::string msg = "still initializing"; Status result = hbResp.initialize(BSON("ok" << 1.0 << "opTime" << OpTime())); ASSERT_EQUALS(ErrorCodes::NoSuchKey, result.code()); ASSERT_TRUE(stringContains(result.reason(), "\"v\"")) << result.reason() << " doesn't contain 'v' field required error msg"; } TEST(ReplSetHeartbeatResponse, MismatchedRepliSetNames) { ReplSetHeartbeatResponse hbResponse; BSONObj initializerObj = BSON("ok" << 0.0 << "mismatch" << true); Status result = hbResponse.initialize(initializerObj); ASSERT_EQUALS(ErrorCodes::InconsistentReplicaSetNames, result.code()); } TEST(ReplSetHeartbeatResponse, AuthFailure) { ReplSetHeartbeatResponse hbResp; std::string errMsg = "Unauthorized"; Status result = hbResp.initialize(BSON("ok" << 0.0 << "errmsg" << errMsg << "code" << ErrorCodes::Unauthorized)); ASSERT_EQUALS(ErrorCodes::Unauthorized, result.code()); ASSERT_EQUALS(errMsg, result.reason()); } TEST(ReplSetHeartbeatResponse, ServerError) { ReplSetHeartbeatResponse hbResp; std::string errMsg = "Random Error"; Status result = hbResp.initialize(BSON("ok" << 0.0 << "errmsg" << errMsg )); ASSERT_EQUALS(ErrorCodes::UnknownError, result.code()); ASSERT_EQUALS(errMsg, result.reason()); } } // namespace } // namespace repl } // namespace mongo