Skip to content

Commit 90ba3df

Browse files
author
matt dannenberg
committed
SERVER-15062 prepareHeartbeatResponse testing
1 parent a6b0f47 commit 90ba3df

File tree

4 files changed

+226
-6
lines changed

4 files changed

+226
-6
lines changed

src/mongo/db/repl/topology_coordinator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -312,7 +312,8 @@ namespace repl {
312312
// Testing interface
313313
//
314314
////////////////////////////////////////////////////////////
315-
virtual void changeMemberState_forTest(const MemberState& newState) = 0;
315+
virtual void changeMemberState_forTest(const MemberState& newState,
316+
OpTime electionTime = OpTime(0,0)) = 0;
316317

317318
protected:
318319
TopologyCoordinator() {}

src/mongo/db/repl/topology_coordinator_impl.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,8 @@ namespace {
10221022
return maxIndex;
10231023
}
10241024

1025-
void TopologyCoordinatorImpl::changeMemberState_forTest(const MemberState& newMemberState) {
1025+
void TopologyCoordinatorImpl::changeMemberState_forTest(const MemberState& newMemberState,
1026+
OpTime electionTime) {
10261027
invariant(_selfIndex != -1);
10271028
if (newMemberState == getMemberState())
10281029
return;
@@ -1034,7 +1035,7 @@ namespace {
10341035
hbData.getLastHeartbeat(),
10351036
OID(),
10361037
OpTime(0, 0),
1037-
OpTime(0, 0));
1038+
electionTime);
10381039
invariant(_role == Role::leader);
10391040
break;
10401041
case MemberState::RS_SECONDARY:

src/mongo/db/repl/topology_coordinator_impl.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ namespace repl {
197197
////////////////////////////////////////////////////////////
198198

199199
// Changes _memberState to newMemberState. Only for testing.
200-
virtual void changeMemberState_forTest(const MemberState& newMemberState);
200+
void changeMemberState_forTest(const MemberState& newMemberState,
201+
OpTime electionTime = OpTime(0,0));
201202

202203
// Sets "_electionTime" to "newElectionTime". Only for testing.
203204
void _setElectionTime(const OpTime& newElectionTime);

src/mongo/db/repl/topology_coordinator_impl_test.cpp

Lines changed: 219 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,8 @@ namespace {
7878
}
7979

8080
void makeSelfPrimary(const OpTime& electionOpTime = OpTime(0,0)) {
81-
setSelfMemberState(MemberState::RS_PRIMARY);
81+
getTopoCoord().changeMemberState_forTest(MemberState::RS_PRIMARY, electionOpTime);
8282
getTopoCoord()._setCurrentPrimaryForTest(_selfIndex);
83-
getTopoCoord()._setElectionTime(electionOpTime);
8483
}
8584

8685
void setSelfMemberState(const MemberState& newState) {
@@ -2042,6 +2041,224 @@ namespace {
20422041
ASSERT_TRUE(response.obj().isEmpty());
20432042
}
20442043

2044+
class PrepareHeartbeatResponseTest : public TopoCoordTest {
2045+
public:
2046+
2047+
virtual void setUp() {
2048+
TopoCoordTest::setUp();
2049+
updateConfig(BSON("_id" << "rs0" <<
2050+
"version" << 1 <<
2051+
"members" << BSON_ARRAY(
2052+
BSON("_id" << 10 << "host" << "hself") <<
2053+
BSON("_id" << 20 << "host" << "h2") <<
2054+
BSON("_id" << 30 << "host" << "h3"))),
2055+
0);
2056+
setSelfMemberState(MemberState::RS_SECONDARY);
2057+
}
2058+
2059+
void prepareHeartbeatResponse(const ReplSetHeartbeatArgs& args,
2060+
OpTime lastOpApplied,
2061+
ReplSetHeartbeatResponse* response,
2062+
Status* result) {
2063+
getTopoCoord().prepareHeartbeatResponse(cbData(),
2064+
now()++,
2065+
args,
2066+
"rs0",
2067+
lastOpApplied,
2068+
response,
2069+
result);
2070+
}
2071+
2072+
};
2073+
2074+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseBadProtocolVersion) {
2075+
// set up args with bad protocol version
2076+
ReplSetHeartbeatArgs args;
2077+
args.setProtocolVersion(3);
2078+
ReplSetHeartbeatResponse response;
2079+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2080+
2081+
// prepare response and check the results
2082+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2083+
ASSERT_EQUALS(ErrorCodes::BadValue, result);
2084+
ASSERT_EQUALS("replset: incompatible replset protocol version: 3", result.reason());
2085+
ASSERT_EQUALS("", response.getHbMsg());
2086+
}
2087+
2088+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseBadSetName) {
2089+
// set up args with incorrect replset name
2090+
ReplSetHeartbeatArgs args;
2091+
args.setProtocolVersion(1);
2092+
args.setSetName("rs1");
2093+
ReplSetHeartbeatResponse response;
2094+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2095+
2096+
// prepare response and check the results, including log messages
2097+
startCapturingLogMessages();
2098+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2099+
stopCapturingLogMessages();
2100+
ASSERT_EQUALS(ErrorCodes::BadValue, result);
2101+
ASSERT_EQUALS("repl set names do not match", result.reason());
2102+
ASSERT_EQUALS(1,
2103+
countLogLinesContaining("replSet set names do not match, ours: rs0; remote "
2104+
"node's: rs1"));
2105+
ASSERT_TRUE(response.isMismatched());
2106+
ASSERT_EQUALS("", response.getHbMsg());
2107+
}
2108+
2109+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseSenderIDMissing) {
2110+
// set up args without a senderID
2111+
ReplSetHeartbeatArgs args;
2112+
args.setProtocolVersion(1);
2113+
args.setSetName("rs0");
2114+
args.setConfigVersion(1);
2115+
ReplSetHeartbeatResponse response;
2116+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2117+
2118+
// prepare response and check the results
2119+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2120+
ASSERT_OK(result);
2121+
ASSERT_FALSE(response.isElectable());
2122+
ASSERT_TRUE(response.isReplSet());
2123+
ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
2124+
ASSERT_EQUALS(OpTime(0,0), response.getOpTime());
2125+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2126+
ASSERT_EQUALS("", response.getHbMsg());
2127+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2128+
ASSERT_EQUALS(1, response.getVersion());
2129+
}
2130+
2131+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseConfigVersionLow) {
2132+
// set up args with a config version lower than ours
2133+
ReplSetHeartbeatArgs args;
2134+
args.setProtocolVersion(1);
2135+
args.setConfigVersion(0);
2136+
args.setSetName("rs0");
2137+
args.setSenderId(20);
2138+
ReplSetHeartbeatResponse response;
2139+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2140+
2141+
// prepare response and check the results
2142+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2143+
ASSERT_OK(result);
2144+
ASSERT_TRUE(response.hasConfig());
2145+
ASSERT_FALSE(response.isElectable());
2146+
ASSERT_TRUE(response.isReplSet());
2147+
ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
2148+
ASSERT_EQUALS(OpTime(0,0), response.getOpTime());
2149+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2150+
ASSERT_EQUALS("", response.getHbMsg());
2151+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2152+
ASSERT_EQUALS(1, response.getVersion());
2153+
}
2154+
2155+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseSenderDown) {
2156+
// set up args with sender down from our perspective
2157+
ReplSetHeartbeatArgs args;
2158+
args.setProtocolVersion(1);
2159+
args.setConfigVersion(1);
2160+
args.setSetName("rs0");
2161+
args.setSenderId(20);
2162+
ReplSetHeartbeatResponse response;
2163+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2164+
2165+
// prepare response and check the results
2166+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2167+
ASSERT_OK(result);
2168+
ASSERT_FALSE(response.isElectable());
2169+
ASSERT_TRUE(response.isReplSet());
2170+
ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
2171+
ASSERT_EQUALS(OpTime(0,0), response.getOpTime());
2172+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2173+
ASSERT_EQUALS("", response.getHbMsg());
2174+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2175+
ASSERT_EQUALS(1, response.getVersion());
2176+
ASSERT_TRUE(response.isStateDisagreement());
2177+
}
2178+
2179+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseSenderUp) {
2180+
// set up args and acknowledge sender
2181+
heartbeatFromMember(HostAndPort("h2"), "rs0", MemberState::RS_SECONDARY, OpTime(0,0));
2182+
ReplSetHeartbeatArgs args;
2183+
args.setProtocolVersion(1);
2184+
args.setConfigVersion(1);
2185+
args.setSetName("rs0");
2186+
args.setSenderId(20);
2187+
ReplSetHeartbeatResponse response;
2188+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2189+
2190+
// prepare response and check the results
2191+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2192+
ASSERT_OK(result);
2193+
// this change to true because we can now see a majority, unlike in the previous cases
2194+
ASSERT_TRUE(response.isElectable());
2195+
ASSERT_TRUE(response.isReplSet());
2196+
ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
2197+
ASSERT_EQUALS(OpTime(0,0), response.getOpTime());
2198+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2199+
ASSERT_EQUALS("", response.getHbMsg());
2200+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2201+
ASSERT_EQUALS(1, response.getVersion());
2202+
}
2203+
2204+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseAsPrimary) {
2205+
makeSelfPrimary(OpTime(10,0));
2206+
heartbeatFromMember(HostAndPort("h2"), "rs0", MemberState::RS_SECONDARY, OpTime(0,0));
2207+
2208+
ReplSetHeartbeatArgs args;
2209+
args.setProtocolVersion(1);
2210+
args.setConfigVersion(1);
2211+
args.setSetName("rs0");
2212+
args.setSenderId(20);
2213+
ReplSetHeartbeatResponse response;
2214+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2215+
2216+
// prepare response and check the results
2217+
prepareHeartbeatResponse(args, OpTime(11,0), &response, &result);
2218+
ASSERT_OK(result);
2219+
// cannot be elected because we are already primary
2220+
ASSERT_FALSE(response.isElectable());
2221+
ASSERT_TRUE(response.isReplSet());
2222+
ASSERT_EQUALS(MemberState::RS_PRIMARY, response.getState().s);
2223+
ASSERT_EQUALS(OpTime(11,0), response.getOpTime());
2224+
ASSERT_EQUALS(OpTime(10,0), response.getElectionTime());
2225+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2226+
ASSERT_EQUALS("", response.getHbMsg());
2227+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2228+
ASSERT_EQUALS(1, response.getVersion());
2229+
}
2230+
2231+
TEST_F(PrepareHeartbeatResponseTest, PrepareHeartbeatResponseWithSyncSource) {
2232+
// get a sync source
2233+
heartbeatFromMember(HostAndPort("h3"), "rs0", MemberState::RS_SECONDARY, OpTime(0,0));
2234+
heartbeatFromMember(HostAndPort("h3"), "rs0", MemberState::RS_SECONDARY, OpTime(0,0));
2235+
heartbeatFromMember(HostAndPort("h2"), "rs0", MemberState::RS_SECONDARY, OpTime(1,0));
2236+
heartbeatFromMember(HostAndPort("h2"), "rs0", MemberState::RS_SECONDARY, OpTime(1,0));
2237+
getTopoCoord().chooseNewSyncSource(now()++, OpTime(0,0));
2238+
2239+
// set up args
2240+
ReplSetHeartbeatArgs args;
2241+
args.setProtocolVersion(1);
2242+
args.setConfigVersion(1);
2243+
args.setSetName("rs0");
2244+
args.setSenderId(20);
2245+
ReplSetHeartbeatResponse response;
2246+
Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
2247+
2248+
// prepare response and check the results
2249+
prepareHeartbeatResponse(args, OpTime(0,0), &response, &result);
2250+
ASSERT_OK(result);
2251+
ASSERT_TRUE(response.isElectable());
2252+
ASSERT_TRUE(response.isReplSet());
2253+
ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
2254+
ASSERT_EQUALS(OpTime(0,0), response.getOpTime());
2255+
ASSERT_EQUALS(Seconds(0).total_milliseconds(), response.getTime().total_milliseconds());
2256+
// changed to a syncing message because our sync source changed recently
2257+
ASSERT_EQUALS("syncing to: h2:27017", response.getHbMsg());
2258+
ASSERT_EQUALS("rs0", response.getReplicaSetName());
2259+
ASSERT_EQUALS(1, response.getVersion());
2260+
ASSERT_EQUALS(HostAndPort("h2").toString(), response.getSyncingTo());
2261+
}
20452262
} // namespace
20462263
} // namespace repl
20472264
} // namespace mongo

0 commit comments

Comments
 (0)