/*
* Copyright © 2014 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.tephra.distributed;
import com.google.common.base.Throwables;
import org.junit.Assert;
import org.junit.Test;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Tests for {@link ElasticPool}.
*/
public class ElasticPoolTest {
static class Dummy {
static AtomicInteger count = new AtomicInteger(0);
boolean valid = true;
Dummy() {
count.incrementAndGet();
}
void markInvalid() {
valid = false;
}
public boolean isValid() {
return valid;
}
}
class DummyPool extends ElasticPool<Dummy, RuntimeException> {
public DummyPool(int sizeLimit) {
super(sizeLimit);
}
@Override
protected Dummy create() {
return new Dummy();
}
@Override
protected boolean recycle(Dummy element) {
return element.isValid();
}
}
@Test(timeout = 5000)
public void testFewerThreadsThanElements() throws InterruptedException {
final DummyPool pool = new DummyPool(5);
Dummy.count.set(0);
createAndRunThreads(2, pool, false);
// we only ran 2 threads, so only 2 elements got created, even though pool size is 5
Assert.assertEquals(2, Dummy.count.get());
}
@Test(timeout = 5000)
public void testMoreThreadsThanElements() throws InterruptedException {
final DummyPool pool = new DummyPool(2);
Dummy.count.set(0);
createAndRunThreads(5, pool, false);
// even though we ran 5 threads, only 2 elements got created because pool size is 2
Assert.assertEquals(2, Dummy.count.get());
}
@Test(timeout = 5000)
public void testMoreThreadsThanElementsWithDiscard() throws InterruptedException {
final DummyPool pool = new DummyPool(2);
Dummy.count.set(0);
int numThreads = 3;
// pass 'true' as the last parameter, which results in the elements being discarded after each obtain() call.
createAndRunThreads(numThreads, pool, true);
// this results in (5 * numThreads) number of elements being created since each thread obtains a client 5 times.
Assert.assertEquals(5 * numThreads, Dummy.count.get());
}
// Creates a list of threads which obtain a client from the pool, sleeps for a certain amount of time, and then
// releases the client back to the pool, optionally marking it invalid before doing so. It repeats this five times.
// Then, runs these threads to completion.
private void createAndRunThreads(int numThreads, final DummyPool pool,
final boolean discardAtEnd) throws InterruptedException {
Thread[] threads = new Thread[numThreads];
for (int i = 0; i < numThreads; i++) {
threads[i] = new Thread() {
@Override
public void run() {
for (int j = 0; j < 5; ++j) {
Dummy dummy;
try {
dummy = pool.obtain();
} catch (InterruptedException e) {
throw Throwables.propagate(e);
}
try {
Thread.sleep(10L);
} catch (InterruptedException e) {
// ignored
}
if (discardAtEnd) {
dummy.markInvalid();
}
pool.release(dummy);
}
}
};
}
for (Thread t : threads) {
t.start();
}
for (Thread t : threads) {
t.join();
}
}
}