package me.prettyprint.cassandra.connection;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import me.prettyprint.cassandra.BaseEmbededServerSetupTest;
import me.prettyprint.cassandra.connection.client.HClient;
import me.prettyprint.cassandra.connection.factory.HClientFactory;
import me.prettyprint.cassandra.service.*;
import me.prettyprint.hector.api.exceptions.HPoolExhaustedException;
import me.prettyprint.hector.api.exceptions.HTimedOutException;
import me.prettyprint.hector.api.exceptions.HectorException;
import org.apache.cassandra.thrift.Cassandra.Client;
import org.apache.commons.lang.mutable.MutableBoolean;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
public class HConnectionManagerTest extends BaseEmbededServerSetupTest {
@Test
public void testRemoveHost() {
setupClient();
CassandraHost cassandraHost = new CassandraHost("127.0.0.1", 9170);
connectionManager.removeCassandraHost(cassandraHost);
assertEquals(0,connectionManager.getActivePools().size());
assertTrue(connectionManager.addCassandraHost(cassandraHost));
assertEquals(1,connectionManager.getActivePools().size());
connectionManager.markHostAsDown(cassandraHost);
assertTrue(connectionManager.removeCassandraHost(cassandraHost));
}
@Test
public void testAddCassandraHostFail() {
setupClient();
CassandraHost cassandraHost = new CassandraHost("127.0.0.1", 9180);
assertFalse(connectionManager.addCassandraHost(cassandraHost));
}
@Test(expected=IllegalArgumentException.class)
public void testNullHostList() {
new HConnectionManager(clusterName, new CassandraHostConfigurator());
}
@Test
public void testMarkHostDownWithNoRetry() {
cassandraHostConfigurator = new CassandraHostConfigurator("127.0.0.1:9170");
cassandraHostConfigurator.setRetryDownedHosts(false);
connectionManager = new HConnectionManager(clusterName, cassandraHostConfigurator);
new CassandraHost("127.0.0.1", 9170);
HClient client = connectionManager.borrowClient();
connectionManager.markHostAsDown(client.getCassandraHost());
assertEquals(0,connectionManager.getActivePools().size());
}
@Test
public void testSuspendCassandraHost() {
setupClient();
CassandraHost cassandraHost = new CassandraHost("127.0.0.1", 9170);
assertTrue(connectionManager.suspendCassandraHost(cassandraHost));
assertEquals(1,connectionManager.getSuspendedCassandraHosts().size());
assertTrue(connectionManager.unsuspendCassandraHost(cassandraHost));
}
@Test(expected=HTimedOutException.class)
public void testTimedOutOperateWithFailover() {
setupClient();
FailoverPolicy fp = FailoverPolicy.ON_FAIL_TRY_ONE_NEXT_AVAILABLE;
connectionManager.operateWithFailover(new TimeoutOp(fp));
}
@Test
public void clientPoolShouldBeSuspendedWhenExhaustedForTooLong() throws InterruptedException {
final int maxActive = 5;
CassandraHostConfigurator configurator = new CassandraHostConfigurator("127.0.0.1:9170");
configurator.setClientFactoryClass(TestClientFactory.class.getName());
configurator.setMaxActive(maxActive);
configurator.setMaxWaitTimeWhenExhausted(50);
configurator.setMaxExhaustedTimeBeforeMarkingAsDown(0);
configurator.setRetryDownedHosts(false);
final HConnectionManager connectionManager = new HConnectionManager("TestCluster", configurator);
CassandraHost host = connectionManager.getHosts().iterator().next();
ConnectionManagerListener listener = mock(ConnectionManagerListener.class);
final MutableBoolean wasRemoved = new MutableBoolean();
doAnswer(new Answer() {
@Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
wasRemoved.setValue(true);
return null;
}
}).when(listener).onHostDown(host);
connectionManager.addListener("TestListener", listener);
ExecutorService exec = Executors.newCachedThreadPool();
final CountDownLatch latch = new CountDownLatch(1);
for (int i = 0; i < maxActive + 1; i++) {
exec.execute(new Runnable() {
@Override
public void run() {
try {
connectionManager.operateWithFailover(new InfiniteOp(FailoverPolicy.FAIL_FAST));
} catch (HPoolExhaustedException e) {
latch.countDown();
}
}
});
Thread.sleep(50);
}
latch.await();
assertTrue(wasRemoved.booleanValue());
exec.shutdownNow();
}
public static class TestClientFactory implements HClientFactory {
@Override
public HClient createClient(final CassandraHost ch) {
HClient client = mock(HClient.class);
when(client.close()).thenReturn(client);
when(client.open()).thenReturn(client);
when(client.isOpen()).thenReturn(true);
when(client.getCassandraHost()).thenReturn(ch);
return client;
}
}
abstract class StubOp extends Operation<String> {
StubOp(FailoverPolicy fp) {
this(OperationType.META_READ);
failoverPolicy = fp;
}
public StubOp(OperationType operationType) {
super(operationType);
}
}
class TimeoutOp extends StubOp {
TimeoutOp(FailoverPolicy fp) {
super(fp);
}
@Override
public String execute(Client cassandra) throws HectorException {
throw new HTimedOutException("fake timeout");
}
}
class InfiniteOp extends StubOp {
InfiniteOp(FailoverPolicy fp) {
super(fp);
}
@Override
public String execute(Client cassandra) throws HectorException {
try {
Thread.sleep(Long.MAX_VALUE);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "";
}
}
}