/* * Copyright (C) 2012-2015 DataStax Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.datastax.driver.core; import com.datastax.driver.core.exceptions.NoHostAvailableException; import com.datastax.driver.core.policies.ConstantReconnectionPolicy; import com.datastax.driver.core.policies.ExponentialReconnectionPolicy; import com.datastax.driver.core.policies.ReconnectionPolicy; import org.testng.annotations.Test; import static com.datastax.driver.core.CreateCCM.TestMode.PER_METHOD; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; @CreateCCM(PER_METHOD) @CCMConfig(dirtiesContext = true, createKeyspace = false) @SuppressWarnings("unused") public class ReconnectionPolicyTest extends AbstractPoliciesTest { private Cluster.Builder exponential() { return Cluster.builder().withReconnectionPolicy(new ExponentialReconnectionPolicy(2 * 1000, 5 * 60 * 1000)); } private Cluster.Builder constant() { return Cluster.builder().withReconnectionPolicy(new ConstantReconnectionPolicy(10 * 1000)); } /* * Test the ExponentialReconnectionPolicy. */ @Test(groups = "long") @CCMConfig(clusterProvider = "exponential") public void exponentialReconnectionPolicyTest() throws Throwable { // Ensure that ExponentialReconnectionPolicy is what we should be testing if (!(cluster().getConfiguration().getPolicies().getReconnectionPolicy() instanceof ExponentialReconnectionPolicy)) { fail("Set policy does not match retrieved policy."); } // Test basic getters ExponentialReconnectionPolicy reconnectionPolicy = (ExponentialReconnectionPolicy) cluster().getConfiguration().getPolicies().getReconnectionPolicy(); assertTrue(reconnectionPolicy.getBaseDelayMs() == 2 * 1000); assertTrue(reconnectionPolicy.getMaxDelayMs() == 5 * 60 * 1000); // Test erroneous instantiations try { new ExponentialReconnectionPolicy(-1, 1); fail(); } catch (IllegalArgumentException e) { //ok } try { new ExponentialReconnectionPolicy(1, -1); fail(); } catch (IllegalArgumentException e) { //ok } try { new ExponentialReconnectionPolicy(-1, -1); fail(); } catch (IllegalArgumentException e) { //ok } try { new ExponentialReconnectionPolicy(2, 1); fail(); } catch (IllegalArgumentException e) { //ok } // Test nextDelays() ReconnectionPolicy.ReconnectionSchedule schedule = new ExponentialReconnectionPolicy(2 * 1000, 5 * 60 * 1000).newSchedule(); assertTrue(schedule.nextDelayMs() == 2000); assertTrue(schedule.nextDelayMs() == 4000); assertTrue(schedule.nextDelayMs() == 8000); assertTrue(schedule.nextDelayMs() == 16000); assertTrue(schedule.nextDelayMs() == 32000); for (int i = 0; i < 64; ++i) schedule.nextDelayMs(); assertTrue(schedule.nextDelayMs() == reconnectionPolicy.getMaxDelayMs()); // Run integration test long restartTime = 2 + 4 + 8 + 2; // 16: 3 full cycles + 2 seconds long retryTime = 30; // 4th cycle start time long breakTime = 62; // time until next reconnection attempt // TODO: Try to sort out variance //reconnectionPolicyTest(restartTime, retryTime, breakTime); } /* * Test the ConstantReconnectionPolicy. */ @Test(groups = "long") @CCMConfig(clusterProvider = "constant") public void constantReconnectionPolicyTest() throws Throwable { // Ensure that ConstantReconnectionPolicy is what we should be testing if (!(cluster().getConfiguration().getPolicies().getReconnectionPolicy() instanceof ConstantReconnectionPolicy)) { fail("Set policy does not match retrieved policy."); } // Test basic getters ConstantReconnectionPolicy reconnectionPolicy = (ConstantReconnectionPolicy) cluster().getConfiguration().getPolicies().getReconnectionPolicy(); assertTrue(reconnectionPolicy.getConstantDelayMs() == 10 * 1000); // Test erroneous instantiations try { new ConstantReconnectionPolicy(-1); fail(); } catch (IllegalArgumentException e) { //ok } // Test nextDelays() ReconnectionPolicy.ReconnectionSchedule schedule = new ConstantReconnectionPolicy(10 * 1000).newSchedule(); assertTrue(schedule.nextDelayMs() == 10000); assertTrue(schedule.nextDelayMs() == 10000); assertTrue(schedule.nextDelayMs() == 10000); assertTrue(schedule.nextDelayMs() == 10000); assertTrue(schedule.nextDelayMs() == 10000); // Run integration test long restartTime = 32; // matches the above test long retryTime = 40; // 2nd cycle start time long breakTime = 10; // time until next reconnection attempt // TODO: Try to sort out variance //reconnectionPolicyTest(restartTime, retryTime, breakTime); } public void reconnectionPolicyTest(long restartTime, long retryTime, long breakTime) throws Throwable { createSchema(1); init(12); query(12); // Ensure a basic test works assertQueried(TestUtils.IP_PREFIX + '1', 12); resetCoordinators(); ccm().forceStop(1); // Start timing and ensure that the node is down long startTime = 0; try { startTime = System.nanoTime() / 1000000000; query(12); fail("Test race condition where node has not shut off quickly enough."); } catch (NoHostAvailableException e) { //ok } long thisTime; boolean restarted = false; while (true) { thisTime = System.nanoTime() / 1000000000; // Restart node at restartTime if (!restarted && thisTime - startTime > restartTime) { ccm().start(1); restarted = true; } // Continue testing queries each second try { query(12); assertQueried(TestUtils.IP_PREFIX + '1', 12); resetCoordinators(); // Ensure the time when the query completes successfully is what was expected assertTrue(retryTime - 2 < thisTime - startTime && thisTime - startTime < retryTime + 2, String.format("Waited %s seconds instead an expected %s seconds wait", thisTime - startTime, retryTime)); } catch (NoHostAvailableException e) { Thread.sleep(1000); continue; } Thread.sleep(breakTime); // The the same query once more, just to be sure query(12); assertQueried(TestUtils.IP_PREFIX + '1', 12); resetCoordinators(); // Ensure the reconnection times reset ccm().forceStop(1); // Start timing and ensure that the node is down startTime = 0; try { startTime = System.nanoTime() / 1000000000; query(12); fail("Test race condition where node has not shut off quickly enough."); } catch (NoHostAvailableException e) { //ok } restarted = false; while (true) { thisTime = System.nanoTime() / 1000000000; // Restart node at restartTime if (!restarted && thisTime - startTime > restartTime) { ccm().start(1); restarted = true; } // Continue testing queries each second try { query(12); assertQueried(TestUtils.IP_PREFIX + '1', 12); resetCoordinators(); // Ensure the time when the query completes successfully is what was expected assertTrue(retryTime - 2 < thisTime - startTime && thisTime - startTime < retryTime + 2, String.format("Waited %s seconds instead an expected %s seconds wait", thisTime - startTime, retryTime)); } catch (NoHostAvailableException e) { Thread.sleep(1000); continue; } break; } break; } } }