package com.lambdaworks.redis.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.fail;
import java.lang.reflect.Proxy;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.apache.commons.pool2.impl.SoftReferenceObjectPool;
import org.junit.Test;
import com.lambdaworks.TestClientResources;
import com.lambdaworks.redis.*;
import com.lambdaworks.redis.api.StatefulRedisConnection;
import com.lambdaworks.redis.api.async.RedisAsyncCommands;
import com.lambdaworks.redis.api.rx.RedisReactiveCommands;
import com.lambdaworks.redis.api.sync.RedisCommands;
import com.lambdaworks.redis.cluster.RedisAdvancedClusterAsyncCommandsImpl;
import com.lambdaworks.redis.cluster.RedisAdvancedClusterReactiveCommandsImpl;
import com.lambdaworks.redis.cluster.RedisClusterClient;
import com.lambdaworks.redis.cluster.StatefulRedisClusterConnectionImpl;
import com.lambdaworks.redis.cluster.api.StatefulRedisClusterConnection;
import com.lambdaworks.redis.cluster.api.async.RedisAdvancedClusterAsyncCommands;
import com.lambdaworks.redis.cluster.api.rx.RedisAdvancedClusterReactiveCommands;
import com.lambdaworks.redis.cluster.api.sync.RedisAdvancedClusterCommands;
import com.lambdaworks.redis.codec.StringCodec;
import com.lambdaworks.redis.masterslave.MasterSlave;
import com.lambdaworks.redis.masterslave.StatefulRedisMasterSlaveConnection;
/**
* @author Mark Paluch
*/
public class ConnectionPoolSupportTest extends AbstractRedisClientTest {
@Test
public void genericPoolShouldWorkWithWrappedConnections() throws Exception {
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
sync.ping();
sync.close();
pool.close();
}
@Test
public void genericPoolUsingWrappingShouldPropagateExceptionsCorrectly() throws Exception {
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
sync.set(key, value);
try {
sync.hgetall(key);
fail("Missing RedisCommandExecutionException");
} catch (RedisCommandExecutionException e) {
assertThat(e).hasMessageContaining("WRONGTYPE");
}
sync.close();
pool.close();
}
@Test
public void wrappedConnectionShouldUseWrappers() throws Exception {
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig());
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
assertThat(connection).isInstanceOf(StatefulRedisConnection.class)
.isNotInstanceOf(StatefulRedisClusterConnectionImpl.class);
assertThat(Proxy.isProxyClass(connection.getClass())).isTrue();
assertThat(sync).isInstanceOf(RedisCommands.class);
assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isNotInstanceOf(RedisAsyncCommandsImpl.class);
assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class)
.isNotInstanceOf(RedisReactiveCommandsImpl.class);
assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class)
.isNotInstanceOf(StatefulRedisConnectionImpl.class).isSameAs(connection);
sync.close();
pool.close();
}
@Test
public void wrappedMasterSlaveConnectionShouldUseWrappers() throws Exception {
GenericObjectPool<StatefulRedisMasterSlaveConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> MasterSlave.connect(client, new StringCodec(), RedisURI.create(host, port)),
new GenericObjectPoolConfig());
StatefulRedisMasterSlaveConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
assertThat(connection).isInstanceOf(StatefulRedisMasterSlaveConnection.class);
assertThat(Proxy.isProxyClass(connection.getClass())).isTrue();
assertThat(sync).isInstanceOf(RedisCommands.class);
assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isNotInstanceOf(RedisAsyncCommandsImpl.class);
assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class)
.isNotInstanceOf(RedisReactiveCommandsImpl.class);
assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class)
.isNotInstanceOf(StatefulRedisConnectionImpl.class).isSameAs(connection);
sync.close();
pool.close();
}
@Test
public void wrappedClusterConnectionShouldUseWrappers() throws Exception {
RedisClusterClient redisClusterClient = RedisClusterClient.create(TestClientResources.create(),
RedisURI.create(TestSettings.host(), 7379));
GenericObjectPool<StatefulRedisClusterConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(redisClusterClient::connect, new GenericObjectPoolConfig());
StatefulRedisClusterConnection<String, String> connection = pool.borrowObject();
RedisAdvancedClusterCommands<String, String> sync = connection.sync();
assertThat(connection).isInstanceOf(StatefulRedisClusterConnection.class)
.isNotInstanceOf(StatefulRedisClusterConnectionImpl.class);
assertThat(Proxy.isProxyClass(connection.getClass())).isTrue();
assertThat(sync).isInstanceOf(RedisAdvancedClusterCommands.class);
assertThat(connection.async()).isInstanceOf(RedisAdvancedClusterAsyncCommands.class)
.isNotInstanceOf(RedisAdvancedClusterAsyncCommandsImpl.class);
assertThat(connection.reactive()).isInstanceOf(RedisAdvancedClusterReactiveCommands.class)
.isNotInstanceOf(RedisAdvancedClusterReactiveCommandsImpl.class);
assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisClusterConnection.class)
.isNotInstanceOf(StatefulRedisClusterConnectionImpl.class).isSameAs(connection);
sync.close();
pool.close();
FastShutdown.shutdown(redisClusterClient);
}
@Test
public void plainConnectionShouldNotUseWrappers() throws Exception {
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig(), false);
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
assertThat(connection).isInstanceOf(StatefulRedisConnection.class)
.isNotInstanceOf(StatefulRedisClusterConnectionImpl.class);
assertThat(Proxy.isProxyClass(connection.getClass())).isFalse();
assertThat(sync).isInstanceOf(RedisCommands.class);
assertThat(connection.async()).isInstanceOf(RedisAsyncCommands.class).isInstanceOf(RedisAsyncCommandsImpl.class);
assertThat(connection.reactive()).isInstanceOf(RedisReactiveCommands.class)
.isInstanceOf(RedisReactiveCommandsImpl.class);
assertThat(sync.getStatefulConnection()).isInstanceOf(StatefulRedisConnection.class)
.isInstanceOf(StatefulRedisConnectionImpl.class);
pool.returnObject(connection);
pool.close();
}
@Test
public void softRefPoolShouldWorkWithWrappedConnections() throws Exception {
SoftReferenceObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createSoftReferenceObjectPool(() -> client.connect());
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
sync.ping();
sync.close();
pool.close();
}
@Test
public void wrappedObjectClosedAfterReturn() throws Exception {
GenericObjectPool<StatefulRedisConnection<String, String>> pool = ConnectionPoolSupport
.createGenericObjectPool(() -> client.connect(), new GenericObjectPoolConfig(), true);
StatefulRedisConnection<String, String> connection = pool.borrowObject();
RedisCommands<String, String> sync = connection.sync();
sync.ping();
sync.close();
try {
connection.isMulti();
fail("Missing RedisException");
} catch (RedisException e) {
assertThat(e).hasMessageContaining("deallocated");
}
pool.close();
}
}