package test.utils.lang.pool;
import com.firefly.utils.concurrent.Promise;
import com.firefly.utils.concurrent.ThreadUtils;
import com.firefly.utils.exception.CommonRuntimeException;
import com.firefly.utils.lang.pool.AsynchronousPool;
import com.firefly.utils.lang.pool.BoundedAsynchronousPool;
import com.firefly.utils.lang.pool.PooledObject;
import org.junit.Assert;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
/**
* @author Pengtao Qiu
*/
public class TestAsyncPool {
@Test
public void testBoundedAsynchronousPool() throws ExecutionException, InterruptedException {
BoundedAsynchronousPool<TestPooledObject> pool = createPool(10);
List<PooledObject<TestPooledObject>> list = new ArrayList<>();
for (int j = 0; j < 4; j++) {
PooledObject<TestPooledObject> o = pool.take().get();
o.getObject().closed = true;
list.add(o);
}
list.forEach(pool::release);
list = new ArrayList<>();
for (int j = 0; j < 3; j++) {
PooledObject<TestPooledObject> o = pool.take().get();
list.add(o);
}
list.forEach(pool::release);
Assert.assertThat(pool.size(), is(pool.getCreatedObjectSize()));
System.out.println(pool.size());
Assert.assertThat(pool.size(), is(4));
pool.stop();
}
@Test
public void testAsynchronousPool() throws InterruptedException, ExecutionException {
AsynchronousPool<TestPooledObject> pool = createPool(10);
PooledObject<TestPooledObject> o = pool.take().get();
Assert.assertThat(pool.size(), is(0));
pool.release(o);
Assert.assertThat(pool.size(), is(1));
System.out.println("o -> " + o.getObject().i);
PooledObject<TestPooledObject> o2 = pool.take().get();
Assert.assertThat(o, is(o2));
pool.release(o2);
System.out.println("o2 -> " + o2.getObject().i);
List<PooledObject<TestPooledObject>> list = new ArrayList<>();
for (int j = 0; j < 10; j++) {
PooledObject<TestPooledObject> o3 = pool.take().get();
System.out.println(o3.getObject().i + "|" + o3.getObject().closed);
list.add(o3);
}
list.forEach(pool::release);
System.out.println("-------------------");
for (int j = 0; j < 10; j++) {
PooledObject<TestPooledObject> o3 = pool.take().get();
System.out.println(o3.getObject().i + "|" + o3.getObject().closed);
}
pool.stop();
Assert.assertThat(pool.size(), is(0));
}
@Test
public void testCompletable() throws ExecutionException, InterruptedException {
Promise.Completable<String> completable = new Promise.Completable<>();
completable.succeeded("hello");
completable.thenAccept(str -> Assert.assertThat(str, is("hello")));
Assert.assertThat(completable.get(), is("hello"));
Assert.assertThat(completable.get(), is("hello"));
completable.thenAccept(str -> Assert.assertThat(str, is("hello")));
completable.thenAccept(str -> Assert.assertThat(str, is("hello")));
completable.thenAccept(str -> Assert.assertThat(str, is("hello")));
completable.thenAccept(str -> Assert.assertThat(str, is("hello")));
completable = new Promise.Completable<>();
completable.exceptionally(t -> {
System.out.println("failure1");
Assert.assertThat(t, instanceOf(CommonRuntimeException.class));
return "failure1";
}).exceptionally(t -> {
System.out.println("failure2");
return "failure2";
});
completable.failed(new CommonRuntimeException("test"));
}
@Test
public void testInvalid() throws Exception {
int maxSize = 8;
AtomicInteger i = new AtomicInteger();
AtomicBoolean start = new AtomicBoolean(true);
TransferQueue<TestPooledObject> queue = new LinkedTransferQueue<>();
BoundedAsynchronousPool<TestPooledObject> pool = new BoundedAsynchronousPool<>(maxSize, () -> {
Promise.Completable<PooledObject<TestPooledObject>> completable = new Promise.Completable<>();
new Thread(() -> {
ThreadUtils.sleep(100L);
int x = i.incrementAndGet();
TestPooledObject obj = new TestPooledObject(x);
queue.offer(obj);
completable.succeeded(new PooledObject<>(obj));
}).start();
return completable;
}, (o) -> !o.getObject().closed, (o) -> {
System.out.println("destory obj - [" + o.getObject().i + "]");
o.getObject().closed = true;
});
new Thread(() -> {
while (start.get()) {
try {
TestPooledObject obj = queue.poll(5, TimeUnit.SECONDS);
if (obj != null) {
ThreadUtils.sleep(100L);
obj.closed = true;
}
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
}).start();
int number = 100;
takeObjectTest(pool, number);
Assert.assertThat(pool.size(), is(maxSize));
Assert.assertThat(pool.size(), is(pool.getCreatedObjectSize()));
System.out.println(pool.size());
start.set(false);
pool.stop();
}
@Test
public void testBoundedAsynchronousPoolException() throws InterruptedException {
AtomicInteger i = new AtomicInteger();
BoundedAsynchronousPool<TestPooledObject> pool = new BoundedAsynchronousPool<>(8, () -> {
Promise.Completable<PooledObject<TestPooledObject>> completable = new Promise.Completable<>();
new Thread(() -> {
ThreadUtils.sleep(100L);
int x = i.incrementAndGet();
if (x % 3 == 0) {
completable.failed(new CommonRuntimeException("test create pooled object: " + x + " exception"));
} else {
completable.succeeded(new PooledObject<>(new TestPooledObject(x)));
}
}).start();
return completable;
}, (o) -> !o.getObject().closed, (o) -> {
System.out.println("destory obj - [" + o.getObject().i + "]");
o.getObject().closed = true;
});
int number = 100;
takeObjectTest(pool, number);
Assert.assertThat(pool.size(), is(6));
Assert.assertThat(pool.size(), is(pool.getCreatedObjectSize()));
System.out.println(pool.size());
pool.stop();
}
private void takeObjectTest(BoundedAsynchronousPool<TestPooledObject> pool, int number) {
Phaser phaser = new Phaser(number + 1);
for (int j = 0; j < number; j++) {
pool.take()
.thenAccept(o -> {
System.out.println("get o: " + o.getObject().i + "| created object size: " + pool.getCreatedObjectSize());
new Thread(() -> {
ThreadUtils.sleep(100L);
phaser.arrive();
pool.release(o);
}).start();
})
.exceptionally(t -> {
phaser.arrive();
System.out.println(t.getMessage());
Assert.assertThat(t, instanceOf(CommonRuntimeException.class));
return null;
});
System.out.println("loop num -> " + j);
}
phaser.arriveAndAwaitAdvance();
}
private BoundedAsynchronousPool<TestPooledObject> createPool(int size) {
AtomicInteger i = new AtomicInteger();
return new BoundedAsynchronousPool<>(size, () -> {
Promise.Completable<PooledObject<TestPooledObject>> completable = new Promise.Completable<>();
completable.succeeded(new PooledObject<>(new TestPooledObject(i.getAndIncrement())));
return completable;
}, (o) -> !o.getObject().closed, (o) -> {
System.out.println("destory obj - [" + o.getObject().i + "]");
o.getObject().closed = true;
});
}
public static class TestPooledObject {
public volatile boolean closed = false;
public final int i;
public TestPooledObject(int i) {
this.i = i;
}
}
}