/* * 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.policies; import com.datastax.driver.core.*; import com.datastax.driver.core.exceptions.*; import org.assertj.core.api.Fail; import org.scassandra.Scassandra; import org.scassandra.http.client.ClosedConnectionConfig; import org.scassandra.http.client.PrimingRequest; import org.scassandra.http.client.Result; import org.scassandra.http.client.UnavailableConfig; import org.testng.Assert; import org.testng.annotations.Test; import java.util.Collections; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; import static org.scassandra.http.client.Consistency.LOCAL_SERIAL; import static org.scassandra.http.client.PrimingRequest.then; import static org.scassandra.http.client.Result.*; public class DefaultRetryPolicyIntegrationTest extends AbstractRetryPolicyIntegrationTest { public DefaultRetryPolicyIntegrationTest() { super(DefaultRetryPolicy.INSTANCE); } @Test(groups = "short") public void should_rethrow_on_read_timeout_with_0_receivedResponses() { simulateError(1, read_request_timeout); try { query(); fail("expected a ReadTimeoutException"); } catch (ReadTimeoutException e) {/*expected*/ } assertOnReadTimeoutWasCalled(1); assertThat(errors.getReadTimeouts().getCount()).isEqualTo(1); assertThat(errors.getRetries().getCount()).isEqualTo(0); assertThat(errors.getRetriesOnReadTimeout().getCount()).isEqualTo(0); assertQueried(1, 1); assertQueried(2, 0); assertQueried(3, 0); } @Test(groups = "short") public void should_rethrow_on_write_timeout_with_SIMPLE_write_type() { simulateError(1, write_request_timeout); try { query(); fail("expected a WriteTimeoutException"); } catch (WriteTimeoutException e) {/*expected*/} assertOnWriteTimeoutWasCalled(1); assertThat(errors.getWriteTimeouts().getCount()).isEqualTo(1); assertThat(errors.getRetries().getCount()).isEqualTo(0); assertThat(errors.getRetriesOnWriteTimeout().getCount()).isEqualTo(0); assertQueried(1, 1); assertQueried(2, 0); assertQueried(3, 0); } @Test(groups = "short") public void should_try_next_host_on_first_unavailable() { simulateError(1, unavailable); simulateNormalResponse(2); query(); assertOnUnavailableWasCalled(1); assertThat(errors.getUnavailables().getCount()).isEqualTo(1); assertThat(errors.getRetries().getCount()).isEqualTo(1); assertThat(errors.getRetriesOnUnavailable().getCount()).isEqualTo(1); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 0); } @Test(groups = "short") public void should_rethrow_on_second_unavailable() { simulateError(1, unavailable); simulateError(2, unavailable); try { query(); fail("expected an UnavailableException"); } catch (UnavailableException e) {/*expected*/} assertOnUnavailableWasCalled(2); assertThat(errors.getUnavailables().getCount()).isEqualTo(2); assertThat(errors.getRetries().getCount()).isEqualTo(1); assertThat(errors.getRetriesOnUnavailable().getCount()).isEqualTo(1); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 0); } @Test(groups = "short") public void should_rethrow_unavailable_in_no_host_available_exception() { LoadBalancingPolicy firstHostOnlyPolicy = new WhiteListPolicy(Policies.defaultLoadBalancingPolicy(), Collections.singletonList(host1.getSocketAddress())); Cluster whiteListedCluster = Cluster.builder() .addContactPoints(scassandras.address(1).getAddress()) .withPort(scassandras.getBinaryPort()) .withRetryPolicy(retryPolicy) .withLoadBalancingPolicy(firstHostOnlyPolicy) .build(); try { Session whiteListedSession = whiteListedCluster.connect(); // Clear all activity as result of connect. for (Scassandra node : scassandras.nodes()) { node.activityClient().clearAllRecordedActivity(); } simulateError(1, unavailable); try { query(whiteListedSession); fail("expected an NoHostAvailableException"); } catch (NoHostAvailableException e) { // ok Throwable error = e.getErrors().get(host1.getSocketAddress()); assertThat(error).isNotNull(); assertThat(error).isInstanceOf(UnavailableException.class); } assertOnUnavailableWasCalled(1); // We expect a retry, but it was never sent because there were no more hosts. Metrics.Errors whiteListErrors = whiteListedCluster.getMetrics().getErrorMetrics(); assertThat(whiteListErrors.getRetriesOnUnavailable().getCount()).isEqualTo(1); assertQueried(1, 1); assertQueried(2, 0); assertQueried(3, 0); } finally { whiteListedCluster.close(); } } @Test(groups = "short") public void should_try_next_host_on_client_timeouts() { cluster.getConfiguration().getSocketOptions().setReadTimeoutMillis(1); try { scassandras .node(1).primingClient().prime(PrimingRequest.queryBuilder() .withQuery("mock query") .withThen(then().withFixedDelay(1000L).withRows(row("result", "result1"))) .build()); scassandras .node(2).primingClient().prime(PrimingRequest.queryBuilder() .withQuery("mock query") .withThen(then().withFixedDelay(1000L).withRows(row("result", "result2"))) .build()); scassandras .node(3).primingClient().prime(PrimingRequest.queryBuilder() .withQuery("mock query") .withThen(then().withFixedDelay(1000L).withRows(row("result", "result3"))) .build()); try { query(); fail("expected a NoHostAvailableException"); } catch (NoHostAvailableException e) { assertThat(e.getErrors().keySet()).hasSize(3).containsOnly( host1.getSocketAddress(), host2.getSocketAddress(), host3.getSocketAddress()); assertThat(e.getErrors().values()) .hasOnlyElementsOfType(OperationTimedOutException.class) .extractingResultOf("getMessage") .containsOnlyOnce( String.format("[%s] Timed out waiting for server response", host1.getSocketAddress()), String.format("[%s] Timed out waiting for server response", host2.getSocketAddress()), String.format("[%s] Timed out waiting for server response", host3.getSocketAddress()) ); } assertOnRequestErrorWasCalled(3, OperationTimedOutException.class); assertThat(errors.getRetries().getCount()).isEqualTo(3); assertThat(errors.getClientTimeouts().getCount()).isEqualTo(3); assertThat(errors.getRetriesOnClientTimeout().getCount()).isEqualTo(3); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 1); } finally { cluster.getConfiguration().getSocketOptions().setReadTimeoutMillis(SocketOptions.DEFAULT_READ_TIMEOUT_MILLIS); } } @Test(groups = "short", dataProvider = "serverSideErrors") public void should_try_next_host_on_server_side_error(Result error, Class<? extends DriverException> exception) { simulateError(1, error); simulateError(2, error); simulateError(3, error); try { query(); Fail.fail("expected a NoHostAvailableException"); } catch (NoHostAvailableException e) { assertThat(e.getErrors().keySet()).hasSize(3).containsOnly( host1.getSocketAddress(), host2.getSocketAddress(), host3.getSocketAddress()); assertThat(e.getErrors().values()).hasOnlyElementsOfType(exception); } assertOnRequestErrorWasCalled(3, exception); assertThat(errors.getOthers().getCount()).isEqualTo(3); assertThat(errors.getRetries().getCount()).isEqualTo(3); assertThat(errors.getRetriesOnOtherErrors().getCount()).isEqualTo(3); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 1); } @Test(groups = "short", dataProvider = "connectionErrors") public void should_try_next_host_on_connection_error(ClosedConnectionConfig.CloseType closeType) { simulateError(1, closed_connection, new ClosedConnectionConfig(closeType)); simulateError(2, closed_connection, new ClosedConnectionConfig(closeType)); simulateError(3, closed_connection, new ClosedConnectionConfig(closeType)); try { query(); Fail.fail("expected a NoHostAvailableException"); } catch (NoHostAvailableException e) { assertThat(e.getErrors().keySet()).hasSize(3).containsOnly( host1.getSocketAddress(), host2.getSocketAddress(), host3.getSocketAddress()); assertThat(e.getErrors().values()).hasOnlyElementsOfType(TransportException.class); } assertOnRequestErrorWasCalled(3, TransportException.class); assertThat(errors.getRetries().getCount()).isEqualTo(3); assertThat(errors.getConnectionErrors().getCount()).isEqualTo(3); assertThat(errors.getIgnoresOnConnectionError().getCount()).isEqualTo(0); assertThat(errors.getRetriesOnConnectionError().getCount()).isEqualTo(3); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 1); } @Test(groups = "short") public void should_rethrow_on_unavailable_if_CAS() { simulateError(1, unavailable, new UnavailableConfig(1, 0, LOCAL_SERIAL)); simulateError(2, unavailable, new UnavailableConfig(1, 0, LOCAL_SERIAL)); try { query(); Assert.fail("expected an UnavailableException"); } catch (UnavailableException e) { assertThat(e.getConsistencyLevel()).isEqualTo(ConsistencyLevel.LOCAL_SERIAL); } assertOnUnavailableWasCalled(2); assertThat(errors.getRetries().getCount()).isEqualTo(1); assertThat(errors.getUnavailables().getCount()).isEqualTo(2); assertThat(errors.getRetriesOnUnavailable().getCount()).isEqualTo(1); assertQueried(1, 1); assertQueried(2, 1); assertQueried(3, 0); } }