summaryrefslogtreecommitdiff
path: root/src/mongo/db/repl/topology_coordinator_v1_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/db/repl/topology_coordinator_v1_test.cpp')
-rw-r--r--src/mongo/db/repl/topology_coordinator_v1_test.cpp259
1 files changed, 256 insertions, 3 deletions
diff --git a/src/mongo/db/repl/topology_coordinator_v1_test.cpp b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
index 4720e7b01b4..6756e50e246 100644
--- a/src/mongo/db/repl/topology_coordinator_v1_test.cpp
+++ b/src/mongo/db/repl/topology_coordinator_v1_test.cpp
@@ -1863,7 +1863,7 @@ public:
TopoCoordTest::setUp();
updateConfig(BSON("_id"
<< "rs0"
- << "version" << 1 << "members"
+ << "version" << initConfigVersion << "term" << initConfigTerm << "members"
<< BSON_ARRAY(BSON("_id" << 10 << "host"
<< "hself")
<< BSON("_id" << 20 << "host"
@@ -1880,6 +1880,9 @@ public:
Status* result) {
*result = getTopoCoord().prepareHeartbeatResponseV1(now()++, args, "rs0", response);
}
+
+ int initConfigVersion = 1;
+ int initConfigTerm = 1;
};
TEST_F(PrepareHeartbeatResponseV1Test,
@@ -2004,7 +2007,52 @@ TEST_F(PrepareHeartbeatResponseV1Test,
PopulateHeartbeatResponseWithFullConfigWhenHeartbeatRequestHasAnOldConfigVersion) {
// set up args with a config version lower than ours
ReplSetHeartbeatArgsV1 args;
- args.setConfigVersion(0);
+ args.setConfigVersion(initConfigVersion - 1);
+ args.setConfigTerm(initConfigTerm);
+ args.setSetName("rs0");
+ args.setSenderId(20);
+ ReplSetHeartbeatResponse response;
+ Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
+
+ // prepare response and check the results
+ prepareHeartbeatResponseV1(args, &response, &result);
+ ASSERT_OK(result);
+ ASSERT_TRUE(response.hasConfig());
+ ASSERT_EQUALS("rs0", response.getReplicaSetName());
+ ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
+ ASSERT_EQUALS(OpTime(), response.getDurableOpTime());
+ ASSERT_EQUALS(0, response.getTerm());
+ ASSERT_EQUALS(1, response.getConfigVersion());
+}
+
+TEST_F(PrepareHeartbeatResponseV1Test,
+ PopulateHeartbeatResponseWithFullConfigWhenHeartbeatRequestHasAnOldConfigTerm) {
+ // set up args with a config version lower than ours
+ ReplSetHeartbeatArgsV1 args;
+ args.setConfigVersion(initConfigVersion);
+ args.setConfigTerm(initConfigTerm - 1);
+ args.setSetName("rs0");
+ args.setSenderId(20);
+ ReplSetHeartbeatResponse response;
+ Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
+
+ // prepare response and check the results
+ prepareHeartbeatResponseV1(args, &response, &result);
+ ASSERT_OK(result);
+ ASSERT_TRUE(response.hasConfig());
+ ASSERT_EQUALS("rs0", response.getReplicaSetName());
+ ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
+ ASSERT_EQUALS(OpTime(), response.getDurableOpTime());
+ ASSERT_EQUALS(0, response.getTerm());
+ ASSERT_EQUALS(1, response.getConfigVersion());
+}
+
+TEST_F(PrepareHeartbeatResponseV1Test,
+ PopulateHeartbeatResponseWithFullConfigWhenHeartbeatRequestHasAnOlderTermButNewerVersion) {
+ // set up args with a config version lower than ours
+ ReplSetHeartbeatArgsV1 args;
+ args.setConfigVersion(initConfigVersion + 1);
+ args.setConfigTerm(initConfigTerm - 1);
args.setSetName("rs0");
args.setSenderId(20);
ReplSetHeartbeatResponse response;
@@ -2026,6 +2074,30 @@ TEST_F(PrepareHeartbeatResponseV1Test,
// set up args with a config version higher than ours
ReplSetHeartbeatArgsV1 args;
args.setConfigVersion(10);
+ args.setConfigTerm(1);
+ args.setSetName("rs0");
+ args.setSenderId(20);
+ ReplSetHeartbeatResponse response;
+ Status result(ErrorCodes::InternalError, "prepareHeartbeatResponse didn't set result");
+
+ // prepare response and check the results
+ prepareHeartbeatResponseV1(args, &response, &result);
+ ASSERT_OK(result);
+ ASSERT_FALSE(response.hasConfig());
+ ASSERT_EQUALS("rs0", response.getReplicaSetName());
+ ASSERT_EQUALS(MemberState::RS_SECONDARY, response.getState().s);
+ ASSERT_EQUALS(OpTime(), response.getDurableOpTime());
+ ASSERT_EQUALS(0, response.getTerm());
+ ASSERT_EQUALS(1, response.getConfigVersion());
+}
+
+TEST_F(PrepareHeartbeatResponseV1Test,
+ PopulateFullHeartbeatResponseWhenHeartbeatRequestHasANewerConfigTerm) {
+ // set up args with a config term higher than ours
+ ReplSetHeartbeatArgsV1 args;
+ args.setConfigVersion(1);
+ args.setConfigTerm(10);
+ args.setTerm(10);
args.setSetName("rs0");
args.setSenderId(20);
ReplSetHeartbeatResponse response;
@@ -3170,7 +3242,7 @@ public:
TopoCoordTest::setUp();
updateConfig(BSON("_id"
<< "rs0"
- << "version" << 5 << "members"
+ << "version" << 5 << "term" << 1 << "members"
<< BSON_ARRAY(BSON("_id" << 0 << "host"
<< "host1:27017")
<< BSON("_id" << 1 << "host"
@@ -3517,6 +3589,187 @@ TEST_F(HeartbeatResponseTestV1, ShouldNotChangeSyncSourceWhenMemberNotInConfig)
HostAndPort("host4"), replMetadata, makeOplogQueryMetadata(), now()));
}
+class HeartbeatResponseReconfigTestV1 : public TopoCoordTest {
+public:
+ virtual void setUp() {
+ TopoCoordTest::setUp();
+ updateConfig(makeRSConfigWithVersionAndTerm(initConfigVersion, initConfigTerm), 0);
+ setSelfMemberState(MemberState::RS_SECONDARY);
+ }
+
+ BSONObj makeRSConfigWithVersionAndTerm(long long version, long long term) {
+ return BSON("_id"
+ << "rs0"
+ << "version" << version << "term" << term << "members"
+ << BSON_ARRAY(BSON("_id" << 0 << "host"
+ << "host1:27017")
+ << BSON("_id" << 1 << "host"
+ << "host2:27017")
+ << BSON("_id" << 2 << "host"
+ << "host3:27017"))
+ << "protocolVersion" << 1 << "settings" << BSON("heartbeatTimeoutSecs" << 5));
+ }
+
+ long long initConfigVersion = 2;
+ long long initConfigTerm = 2;
+};
+
+TEST_F(HeartbeatResponseReconfigTestV1, NodeAcceptsConfigIfVersionInHeartbeatResponseIsNewer) {
+ ReplSetConfig config;
+ long long version = initConfigVersion + 1;
+ long long term = initConfigTerm;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 1)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host2"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host2"), hbResponse);
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::Reconfig);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1, NodeAcceptsConfigIfTermInHeartbeatResponseIsNewer) {
+ ReplSetConfig config;
+ long long version = initConfigVersion;
+ long long term = initConfigTerm + 1;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 1)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host2"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host2"), hbResponse);
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::Reconfig);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1,
+ NodeAcceptsConfigIfVersionInHeartbeatResponseIfNewerAndTermUninitialized) {
+ ReplSetConfig config;
+ long long version = initConfigVersion + 1;
+ long long term = OpTime::kUninitializedTerm;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 1)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host2"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host2"), hbResponse);
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::Reconfig);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1, NodeRejectsConfigInHeartbeatResponseIfVersionIsOlder) {
+ // Older config version, same term.
+ ReplSetConfig config;
+ long long version = (initConfigVersion - 1);
+ long long term = initConfigTerm;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 1)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host2"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host2"), hbResponse);
+ // Don't reconfig to an older config.
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::NoAction);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1, NodeRejectsConfigInHeartbeatResponseIfConfigIsTheSame) {
+ ReplSetConfig config;
+ long long version = initConfigVersion;
+ long long term = initConfigTerm;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 0)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host3"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host3"), hbResponse);
+ // Don't reconfig to the same config.
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::NoAction);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1, NodeRejectsConfigInHeartbeatResponseIfTermIsOlder) {
+ // Older config term, same version
+ ReplSetConfig config;
+ long long version = initConfigVersion;
+ long long term = initConfigTerm - 1;
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 0)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host3"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host3"), hbResponse);
+ // Don't reconfig to an older config.
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::NoAction);
+}
+
+TEST_F(HeartbeatResponseReconfigTestV1,
+ NodeRejectsConfigInHeartbeatResponseIfNewerVersionButOlderTerm) {
+ // Newer version but older term.
+ ReplSetConfig config;
+ long long version = (initConfigVersion + 1);
+ long long term = (initConfigTerm - 1);
+ config.initialize(makeRSConfigWithVersionAndTerm(version, term)).transitional_ignore();
+
+ ReplSetHeartbeatResponse hb;
+ hb.initialize(BSON("ok" << 1 << "v" << 1 << "state" << MemberState::RS_SECONDARY), 0)
+ .transitional_ignore();
+ hb.setConfig(config);
+ hb.setConfigVersion(version);
+ hb.setConfigTerm(term);
+ StatusWith<ReplSetHeartbeatResponse> hbResponse = StatusWith<ReplSetHeartbeatResponse>(hb);
+
+ getTopoCoord().prepareHeartbeatRequestV1(now(), "rs0", HostAndPort("host3"));
+ now() += Milliseconds(1);
+ HeartbeatResponseAction action = getTopoCoord().processHeartbeatResponse(
+ now(), Milliseconds(1), HostAndPort("host3"), hbResponse);
+ // Don't reconfig to an older config.
+ ASSERT_EQ(action.getAction(), HeartbeatResponseAction::NoAction);
+}
+
// TODO(dannenberg) figure out what this is trying to test..
TEST_F(HeartbeatResponseTestV1, ReconfigNodeRemovedBetweenHeartbeatRequestAndRepsonse) {
OpTime election = OpTime(Timestamp(14, 0), 0);