|
23 | 23 | using namespace datastax::internal; |
24 | 24 | using namespace datastax::internal::core; |
25 | 25 |
|
| 26 | +#define FIFTEEN_PERCENT(value) static_cast<double>((value * 115) / 100) |
| 27 | + |
26 | 28 | class ClusterUnitTest : public EventLoopTest { |
27 | 29 | public: |
28 | 30 | ClusterUnitTest() |
@@ -239,6 +241,53 @@ class ClusterUnitTest : public EventLoopTest { |
239 | 241 | mockssandra::Cluster& simple_cluster_; |
240 | 242 | }; |
241 | 243 |
|
| 244 | + class ClusterUnitTestReconnectionPolicy : public ReconnectionPolicy { |
| 245 | + public: |
| 246 | + typedef SharedRefPtr<ClusterUnitTestReconnectionPolicy> Ptr; |
| 247 | + |
| 248 | + ClusterUnitTestReconnectionPolicy() |
| 249 | + : ReconnectionPolicy(ReconnectionPolicy::CONSTANT) |
| 250 | + , reconnection_schedule_count_(0) |
| 251 | + , destroyed_reconnection_schedule_count_(0) |
| 252 | + , scheduled_delay_count_(0) {} |
| 253 | + |
| 254 | + virtual const char* name() const { return "blah"; } |
| 255 | + virtual ReconnectionSchedule* new_reconnection_schedule() { |
| 256 | + ++reconnection_schedule_count_; |
| 257 | + return new ClusterUnitTestReconnectionSchedule(&scheduled_delay_count_, |
| 258 | + &destroyed_reconnection_schedule_count_); |
| 259 | + } |
| 260 | + |
| 261 | + unsigned reconnection_schedule_count() const { return reconnection_schedule_count_; } |
| 262 | + unsigned destroyed_reconnection_schedule_count() const { |
| 263 | + return destroyed_reconnection_schedule_count_; |
| 264 | + } |
| 265 | + unsigned scheduled_delay_count() const { return scheduled_delay_count_; } |
| 266 | + |
| 267 | + private: |
| 268 | + unsigned reconnection_schedule_count_; |
| 269 | + unsigned destroyed_reconnection_schedule_count_; |
| 270 | + unsigned scheduled_delay_count_; |
| 271 | + |
| 272 | + class ClusterUnitTestReconnectionSchedule : public ReconnectionSchedule { |
| 273 | + public: |
| 274 | + ClusterUnitTestReconnectionSchedule(unsigned* delay_count, unsigned* destroyed_count) |
| 275 | + : delay_count_(delay_count) |
| 276 | + , destroyed_count_(destroyed_count) {} |
| 277 | + |
| 278 | + ~ClusterUnitTestReconnectionSchedule() { ++*destroyed_count_; } |
| 279 | + |
| 280 | + virtual uint64_t next_delay_ms() { |
| 281 | + ++*delay_count_; |
| 282 | + return 1; |
| 283 | + } |
| 284 | + |
| 285 | + private: |
| 286 | + unsigned* delay_count_; |
| 287 | + unsigned* destroyed_count_; |
| 288 | + }; |
| 289 | + }; |
| 290 | + |
242 | 291 | static void on_connection_connected(ClusterConnector* connector, Future* future) { |
243 | 292 | if (connector->is_ok()) { |
244 | 293 | future->set(); |
@@ -469,7 +518,7 @@ TEST_F(ClusterUnitTest, ReconnectToDiscoveredHosts) { |
469 | 518 | ReconnectClusterListener::Ptr listener(new ReconnectClusterListener(close_future, &outage_plan)); |
470 | 519 |
|
471 | 520 | ClusterSettings settings; |
472 | | - settings.reconnect_timeout_ms = 1; // Reconnect immediately |
| 521 | + settings.reconnection_policy.reset(new ConstantReconnectionPolicy(1)); // Reconnect immediately |
473 | 522 | settings.control_connection_settings.connection_settings.connect_timeout_ms = |
474 | 523 | 200; // Give enough time for the connection to complete |
475 | 524 |
|
@@ -512,7 +561,7 @@ TEST_F(ClusterUnitTest, ReconnectUpdateHosts) { |
512 | 561 | ReconnectClusterListener::Ptr listener(new ReconnectClusterListener(close_future, &outage_plan)); |
513 | 562 |
|
514 | 563 | ClusterSettings settings; |
515 | | - settings.reconnect_timeout_ms = 1; // Reconnect immediately |
| 564 | + settings.reconnection_policy.reset(new ConstantReconnectionPolicy(1)); // Reconnect immediately |
516 | 565 | settings.control_connection_settings.connection_settings.connect_timeout_ms = |
517 | 566 | 200; // Give enough time for the connection to complete |
518 | 567 |
|
@@ -553,7 +602,8 @@ TEST_F(ClusterUnitTest, CloseDuringReconnect) { |
553 | 602 | Listener::Ptr listener(new Listener(close_future)); |
554 | 603 |
|
555 | 604 | ClusterSettings settings; |
556 | | - settings.reconnect_timeout_ms = 100000; // Make sure we're reconnecting when we close. |
| 605 | + settings.reconnection_policy.reset( |
| 606 | + new ConstantReconnectionPolicy(100000)); // Make sure we're reconnecting when we close. |
557 | 607 |
|
558 | 608 | connector->with_settings(settings)->with_listener(listener.get())->connect(event_loop()); |
559 | 609 |
|
@@ -772,7 +822,7 @@ TEST_F(ClusterUnitTest, DCAwareRecoverOnRemoteHost) { |
772 | 822 | new DCAwarePolicy("dc1", 1, false)); // Allow connection to a single remote host |
773 | 823 | settings.load_balancing_policies.clear(); |
774 | 824 | settings.load_balancing_policies.push_back(settings.load_balancing_policy); |
775 | | - settings.reconnect_timeout_ms = 1; // Reconnect immediately |
| 825 | + settings.reconnection_policy.reset(new ConstantReconnectionPolicy(1)); // Reconnect immediately |
776 | 826 | settings.control_connection_settings.connection_settings.connect_timeout_ms = |
777 | 827 | 200; // Give enough time for the connection to complete |
778 | 828 |
|
@@ -868,3 +918,42 @@ TEST_F(ClusterUnitTest, DisableEventsOnStartup) { |
868 | 918 | connect_future->cluster()->close(); |
869 | 919 | ASSERT_TRUE(close_future->wait_for(WAIT_FOR_TIME)); |
870 | 920 | } |
| 921 | + |
| 922 | +TEST_F(ClusterUnitTest, ReconnectionPolicy) { |
| 923 | + mockssandra::SimpleCluster mock_cluster(simple()); |
| 924 | + ASSERT_EQ(mock_cluster.start_all(), 0); |
| 925 | + |
| 926 | + OutagePlan outage_plan(loop(), &mock_cluster); |
| 927 | + outage_plan.stop_node(1); |
| 928 | + outage_plan.start_node(1); |
| 929 | + outage_plan.stop_node(1); |
| 930 | + outage_plan.start_node(1); |
| 931 | + |
| 932 | + ContactPointList contact_points; |
| 933 | + contact_points.push_back("127.0.0.1"); |
| 934 | + |
| 935 | + Future::Ptr close_future(new Future()); |
| 936 | + Future::Ptr connect_future(new Future()); |
| 937 | + ClusterConnector::Ptr connector( |
| 938 | + new ClusterConnector(contact_points, PROTOCOL_VERSION, |
| 939 | + bind_callback(on_connection_reconnect, connect_future.get()))); |
| 940 | + ReconnectClusterListener::Ptr listener(new ReconnectClusterListener(close_future, &outage_plan)); |
| 941 | + |
| 942 | + ClusterSettings settings; |
| 943 | + settings.reconnection_policy.reset(new ClusterUnitTestReconnectionPolicy()); |
| 944 | + settings.control_connection_settings.connection_settings.connect_timeout_ms = |
| 945 | + 200; // Give enough time for the connection to complete |
| 946 | + connector->with_settings(settings)->with_listener(listener.get())->connect(event_loop()); |
| 947 | + |
| 948 | + ASSERT_TRUE(connect_future->wait_for(WAIT_FOR_TIME)); |
| 949 | + EXPECT_FALSE(connect_future->error()); |
| 950 | + |
| 951 | + ASSERT_TRUE(close_future->wait_for(WAIT_FOR_TIME)); |
| 952 | + |
| 953 | + ClusterUnitTestReconnectionPolicy::Ptr policy( |
| 954 | + static_cast<ClusterUnitTestReconnectionPolicy::Ptr>(settings.reconnection_policy)); |
| 955 | + EXPECT_EQ(2, policy->reconnection_schedule_count()); |
| 956 | + EXPECT_EQ(2, policy->destroyed_reconnection_schedule_count()); |
| 957 | + EXPECT_GE(policy->scheduled_delay_count(), 2u); |
| 958 | + EXPECT_EQ(3, mock_cluster.connection_attempts(1)); // Includes initial connection attempt |
| 959 | +} |
0 commit comments