package redis.netty.client;
import org.junit.Test;
import redis.Command;
import redis.netty.BulkReply;
import redis.netty.IntegerReply;
import redis.netty.StatusReply;
import spullara.util.concurrent.Promise;
import spullara.util.functions.Block;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* Test the base redis client. Default redis required.
*/
public class RedisClientBaseTest {
@Test
public void testConnect() throws Exception {
final CountDownLatch done = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
final AtomicReference<RedisClientBase> client = new AtomicReference<>();
Promise<RedisClientBase> connect = RedisClientBase.connect("localhost", 6379);
connect.onSuccess(new Block<RedisClientBase>() {
@Override
public void apply(RedisClientBase redisClientBase) {
success.set(true);
client.set(redisClientBase);
done.countDown();
}
}).onFailure(new Block<Throwable>() {
@Override
public void apply(Throwable throwable) {
success.set(false);
done.countDown();
}
});
done.await(5000, TimeUnit.MILLISECONDS);
final CountDownLatch done2 = new CountDownLatch(1);
assertTrue(success.get());
client.get().close().onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
success.set(true);
done2.countDown();
}
}).onFailure(new Block<Throwable>() {
@Override
public void apply(Throwable throwable) {
success.set(false);
done2.countDown();
}
});
done2.await(5000, TimeUnit.MILLISECONDS);
assertTrue(success.get());
}
@Test
public void testConnectFailure() throws Exception {
final CountDownLatch done = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
final AtomicReference<Throwable> failure = new AtomicReference<>();
Promise<RedisClientBase> connect = RedisClientBase.connect("localhost", 6380);
connect.onSuccess(new Block<RedisClientBase>() {
@Override
public void apply(RedisClientBase redisClientBase) {
success.set(true);
done.countDown();
}
}).onFailure(new Block<Throwable>() {
@Override
public void apply(Throwable throwable) {
success.set(false);
failure.set(throwable);
done.countDown();
}
});
done.await(5000, TimeUnit.MILLISECONDS);
assertFalse(success.get());
assertTrue("Connection not refused", failure.get().getMessage().startsWith("Connection refused"));
}
@Test
public void testError() throws ExecutionException, InterruptedException {
try {
RedisClient client = RedisClient.connect("localhost", 6379).get();
client.set("test", "value").get();
client.hgetall("test").get();
fail("Should have failed");
} catch (ExecutionException ee) {
assertTrue(ee.getCause() instanceof RedisException);
}
}
@Test
public void testExecute() throws Exception {
final CountDownLatch done = new CountDownLatch(1);
final AtomicBoolean success = new AtomicBoolean();
RedisClientBase.connect("localhost", 6379).onSuccess(new Block<RedisClientBase>() {
@Override
public void apply(final RedisClientBase redisClientBase) {
redisClientBase.execute(StatusReply.class, new Command("set", "test", "test")).onSuccess(new Block<StatusReply>() {
@Override
public void apply(StatusReply reply) {
if (reply.data().equals("OK")) {
redisClientBase.execute(BulkReply.class, new Command("get", "test")).onSuccess(new Block<BulkReply>() {
@Override
public void apply(BulkReply reply) {
if (reply.asAsciiString().equals("test")) {
success.set(true);
}
done.countDown();
redisClientBase.close();
}
});
} else {
done.countDown();
redisClientBase.close();
}
}
});
}
});
done.await(5000, TimeUnit.MILLISECONDS);
assertTrue(success.get());
}
@Test
public void testCommands() throws InterruptedException {
final CountDownLatch done = new CountDownLatch(1);
final AtomicReference<StatusReply> setOK = new AtomicReference<>();
final AtomicReference<BulkReply> getTest2 = new AtomicReference<>();
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
redisClient.set("test", "test2").onSuccess(new Block<StatusReply>() {
@Override
public void apply(StatusReply statusReply) {
setOK.set(statusReply);
redisClient.get("test").onSuccess(new Block<BulkReply>() {
@Override
public void apply(BulkReply bulkReply) {
getTest2.set(bulkReply);
redisClient.close().onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
done.countDown();
}
});
}
});
}
});
}
}).onFailure(new Block<Throwable>() {
@Override
public void apply(Throwable throwable) {
throwable.printStackTrace();
}
});
done.await(5000, TimeUnit.MILLISECONDS);
assertEquals("OK", setOK.get().data());
assertEquals("test2", getTest2.get().asAsciiString());
}
@Test
public void testSerialPerformance() throws InterruptedException {
if (System.getenv().containsKey("CI") || System.getProperty("CI") != null) return;
final CountDownLatch done = new CountDownLatch(1);
final int[] i = new int[1];
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
long start;
private Block<StatusReply> setBlock;
void again(RedisClient redisClient) {
apply(redisClient);
}
@Override
public void apply(final RedisClient redisClient) {
if (start == 0) {
setBlock = new Block<StatusReply>() {
@Override
public void apply(StatusReply statusReply) {
again(redisClient);
}
};
start = System.currentTimeMillis();
}
if (System.currentTimeMillis() - start < 5000) {
redisClient.set(String.valueOf(i[0]++), "test2").onSuccess(setBlock);
} else {
redisClient.close().onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
done.countDown();
}
});
}
}
});
done.await(6000, TimeUnit.MILLISECONDS);
System.out.println("Completed " + i[0] / 5 + " per second");
}
@Test
public void testPipelinePerformance() throws InterruptedException {
if (System.getenv().containsKey("CI") || System.getProperty("CI") != null) return;
final CountDownLatch done = new CountDownLatch(1);
final AtomicInteger total = new AtomicInteger();
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
new Thread(new Runnable() {
@Override
public void run() {
try {
final Semaphore semaphore = new Semaphore(100);
Runnable release = new Runnable() {
@Override
public void run() {
semaphore.release();
}
};
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 5000) {
semaphore.acquire();
String current = String.valueOf(total.getAndIncrement());
redisClient.set(current, current).ensure(release);
}
semaphore.acquire(100);
done.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
});
done.await(6000, TimeUnit.MILLISECONDS);
if (total.get() == 100) {
fail("Failed to complete any requests");
}
System.out.println("Completed " + total.get() / 5 + " per second");
}
@Test
public void testPipelineConcurrency() throws InterruptedException {
if (System.getenv().containsKey("CI") || System.getProperty("CI") != null) return;
final CountDownLatch done = new CountDownLatch(1);
final AtomicInteger total = new AtomicInteger();
final AtomicInteger errors = new AtomicInteger();
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
new Thread(new Runnable() {
@Override
public void run() {
try {
final Semaphore semaphore = new Semaphore(100);
Runnable release = new Runnable() {
@Override
public void run() {
semaphore.release();
}
};
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 5000) {
semaphore.acquire();
final String current = String.valueOf(total.getAndIncrement());
redisClient.set(current, current).ensure(release).onSuccess(new Block<StatusReply>() {
@Override
public void apply(StatusReply statusReply) {
redisClient.get(current).onSuccess(new Block<BulkReply>() {
@Override
public void apply(BulkReply bulkReply) {
String s = bulkReply.asAsciiString();
if (!s.equals(current)) {
System.out.println(s + " != " + current);
errors.incrementAndGet();
}
}
}).onFailure(new Block<Throwable>() {
@Override
public void apply(Throwable throwable) {
errors.incrementAndGet();
}
});
}
});
}
semaphore.acquire(100);
done.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
}
});
done.await(6000, TimeUnit.MILLISECONDS);
System.out.println("Completed " + total.get() / 5 + " per second");
assertEquals(0, errors.get());
if (total.get() == 100) {
fail("Failed to complete any requests");
}
}
@Test
public void testPubSub() throws InterruptedException, ExecutionException {
final CountDownLatch done = new CountDownLatch(2);
final Promise<Void> wassubscribed = new Promise<>();
final AtomicReference<byte[]> gotmessage = new AtomicReference<>();
final AtomicLong listeners = new AtomicLong(0);
final AtomicBoolean failed = new AtomicBoolean();
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
redisClient.addListener(new ReplyListener() {
@Override
public void subscribed(byte[] name, int channels) {
wassubscribed.set(null);
}
@Override
public void psubscribed(byte[] name, int channels) {
failed.set(true);
}
@Override
public void unsubscribed(byte[] name, int channels) {
failed.set(true);
}
@Override
public void punsubscribed(byte[] name, int channels) {
failed.set(true);
}
@Override
public void message(byte[] channel, byte[] message) {
gotmessage.set(message);
redisClient.close();
done.countDown();
}
@Override
public void pmessage(byte[] pattern, byte[] channel, byte[] message) {
failed.set(true);
}
});
redisClient.subscribe("test").onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
wassubscribed.onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
redisClient.publish("test", "hello").onSuccess(new Block<IntegerReply>() {
@Override
public void apply(IntegerReply integerReply) {
listeners.set(integerReply.data());
redisClient.close();
done.countDown();
}
});
}
});
}
});
}
});
}
});
done.await(10000, TimeUnit.MILLISECONDS);
assertTrue(wassubscribed.get() == null);
assertEquals("hello", new String(gotmessage.get()));
assertEquals(1, listeners.get());
assertFalse(failed.get());
}
@Test
public void testPubSubPerformance() throws InterruptedException {
if (System.getenv().containsKey("CI") || System.getProperty("CI") != null) return;
final CountDownLatch done = new CountDownLatch(1);
final Semaphore semaphore = new Semaphore(100);
final AtomicInteger total = new AtomicInteger();
Promise<RedisClient> redisClient = RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(RedisClient redisClient) {
redisClient.addListener(new MessageListener() {
@Override
public void message(byte[] channel, byte[] message) {
semaphore.release();
total.incrementAndGet();
}
@Override
public void pmessage(byte[] pattern, byte[] channel, byte[] message) {
}
});
redisClient.subscribe("test").onSuccess(new Block<Void>() {
@Override
public void apply(Void aVoid) {
RedisClient.connect("localhost", 6379).onSuccess(new Block<RedisClient>() {
@Override
public void apply(final RedisClient redisClient) {
new Thread(new Runnable() {
@Override
public void run() {
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 5000) {
semaphore.acquireUninterruptibly();
redisClient.publish("test", "hello");
}
redisClient.close();
done.countDown();
}
}).start();
}
});
}
});
}
});
done.await(6000, TimeUnit.MILLISECONDS);
redisClient.onSuccess(new Block<RedisClient>() {
@Override
public void apply(RedisClient redisClient) {
redisClient.close();
}
});
System.out.println(total.get() / 5 + " per second");
}
}