/* * 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.google.common.collect.ImmutableMap; import org.scassandra.Scassandra; import org.scassandra.http.client.PrimingRequest; import org.testng.annotations.Test; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import static org.assertj.core.api.Assertions.assertThat; import static org.scassandra.http.client.PrimingRequest.then; public class RequestHandlerTest { @Test(groups = "long") public void should_handle_race_between_response_and_cancellation() { final Scassandra scassandra = TestUtils.createScassandraServer(); Cluster cluster = null; try { // Use a mock server that takes a constant time to reply scassandra.start(); List<Map<String, ?>> rows = Collections.<Map<String, ?>>singletonList(ImmutableMap.of("key", 1)); scassandra.primingClient().prime( PrimingRequest.queryBuilder() .withQuery("mock query") .withThen(then().withRows(rows).withFixedDelay(10L)) .build() ); cluster = Cluster.builder() .addContactPoint(TestUtils.ipOfNode(1)) .withPort(scassandra.getBinaryPort()) .withPoolingOptions(new PoolingOptions() .setCoreConnectionsPerHost(HostDistance.LOCAL, 1) .setMaxConnectionsPerHost(HostDistance.LOCAL, 1) .setHeartbeatIntervalSeconds(0)) .build(); Session session = cluster.connect(); // To reproduce, we need to cancel the query exactly when the reply arrives. // Run a few queries to estimate how much that will take. int samples = 100; long start = System.currentTimeMillis(); for (int i = 0; i < samples; i++) { session.execute("mock query"); } long elapsed = System.currentTimeMillis() - start; long queryDuration = elapsed / samples; // Now run queries and cancel them after that estimated time for (int i = 0; i < 2000; i++) { ResultSetFuture future = session.executeAsync("mock query"); try { future.getUninterruptibly(queryDuration, TimeUnit.MILLISECONDS); } catch (TimeoutException e) { future.cancel(true); } } Connection connection = getSingleConnection(session); assertThat(connection.inFlight.get()).isEqualTo(0); } finally { if (cluster != null) cluster.close(); scassandra.stop(); } } private Connection getSingleConnection(Session session) { HostConnectionPool pool = ((SessionManager) session).pools.values().iterator().next(); return pool.connections.get(0); } }