// Copyright (C) 2011 - Will Glozer.  All rights reserved.

package com.lambdaworks.redis;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

public class AsyncConnectionTest extends AbstractRedisClientTest {
    private RedisAsyncConnection<String, String> async;

    @Rule
    public ExpectedException exception = ExpectedException.none();

    @Before
    public void openAsyncConnection() throws Exception {
        async = client.connectAsync();
    }

    @After
    public void closeAsyncConnection() throws Exception {
        async.close();
    }

    @Test(timeout = 10000)
    public void multi() throws Exception {
        assertThat(async.multi().get()).isEqualTo("OK");
        Future<String> set = async.set(key, value);
        Future<Long> rpush = async.rpush("list", "1", "2");
        Future<List<String>> lrange = async.lrange("list", 0, -1);

        assertThat(!set.isDone() && !rpush.isDone() && !rpush.isDone()).isTrue();
        assertThat(async.exec().get()).isEqualTo(list("OK", 2L, list("1", "2")));

        assertThat(set.get()).isEqualTo("OK");
        assertThat((long) rpush.get()).isEqualTo(2L);
        assertThat(lrange.get()).isEqualTo(list("1", "2"));
    }

    @Test(timeout = 10000)
    public void watch() throws Exception {
        assertThat(async.watch(key).get()).isEqualTo("OK");

        redis.set(key, value + "X");

        async.multi();
        Future<String> set = async.set(key, value);
        Future<Long> append = async.append(key, "foo");
        assertThat(async.exec().get()).isEqualTo(list());
        assertThat(set.get()).isNull();
        assertThat(append.get()).isNull();
    }

    @Test(timeout = 10000)
    public void futureListener() throws Exception {

        final List<Object> run = new ArrayList<Object>();

        Runnable listener = new Runnable() {
            @Override
            public void run() {
                run.add(new Object());
            }
        };

        for (int i = 0; i < 1000; i++) {
            redis.lpush(key, "" + i);
        }

        RedisAsyncConnection<String, String> connection = client.connectAsync();

        Long len = connection.llen(key).get();
        assertThat(len.intValue()).isEqualTo(1000);

        RedisFuture<List<String>> sort = connection.sort(key);
        assertThat(sort.isCancelled()).isFalse();

        sort.thenRun(listener);

        sort.get();
        Thread.sleep(100);

        assertThat(run).hasSize(1);

    }

    @Test(timeout = 1000)
    public void futureListenerCompleted() throws Exception {

        final List<Object> run = new ArrayList<Object>();

        Runnable listener = new Runnable() {
            @Override
            public void run() {
                run.add(new Object());
            }
        };

        RedisAsyncConnection<String, String> connection = client.connectAsync();

        RedisFuture<String> set = connection.set(key, value);
        set.get();

        set.thenRun(listener);

        assertThat(run).hasSize(1);

    }

    @Test(timeout = 100)
    public void discardCompletesFutures() throws Exception {
        async.multi();
        Future<String> set = async.set(key, value);
        async.discard();
        assertThat(set.get()).isNull();
    }

    @Test(timeout = 10000)
    public void awaitAll() throws Exception {
        Future<String> get1 = async.get(key);
        Future<String> set = async.set(key, value);
        Future<String> get2 = async.get(key);
        Future<Long> append = async.append(key, value);

        assertThat(LettuceFutures.awaitAll(1, TimeUnit.SECONDS, get1, set, get2, append)).isTrue();

        assertThat(get1.get()).isNull();
        assertThat(set.get()).isEqualTo("OK");
        assertThat(get2.get()).isEqualTo(value);
        assertThat((long) append.get()).isEqualTo(value.length() * 2);
    }

    @Test(timeout = 100)
    public void awaitAllTimeout() throws Exception {
        Future<KeyValue<String, String>> blpop = async.blpop(1, key);
        assertThat(LettuceFutures.awaitAll(1, TimeUnit.NANOSECONDS, blpop)).isFalse();
    }

}

@@ -3289,33 +3289,33 @@
 @Test(timeout = 
-1
+5
 00)%0A    public v
@@ -4120,17 +4120,17 @@
 meout = 
-1
+5
 00)%0A    

Extend test timeouts