package org.threadly.concurrent;
import static org.junit.Assert.*;
import static org.threadly.TestConstants.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.RejectedExecutionException;
import org.junit.Test;
import org.threadly.BlockingTestRunnable;
import org.threadly.test.concurrent.TestRunnable;
import org.threadly.util.Clock;
@SuppressWarnings("javadoc")
public class UnfairExecutorTest extends SubmitterExecutorInterfaceTest {
@Override
protected SubmitterExecutorFactory getSubmitterExecutorFactory() {
return new UnfairExecutorFactory();
}
@Test
@Override
public void executeInOrderTest() {
// ignored, this test makes no sense for this executor
}
@Test
public void isShutdownTest() {
UnfairExecutor ue = new UnfairExecutor(1);
assertFalse(ue.isShutdown());
executeTestRunnables(ue, 0);
ue.shutdown();
assertTrue(ue.isShutdown());
ue = new UnfairExecutor(1);
ue.shutdownNow();
assertTrue(ue.isShutdown());
}
@Test
public void shutdownTest() {
UnfairExecutor ue = new UnfairExecutor(1);
/* adding a run time to have greater chances that runnable
* will be waiting to execute after shutdown call.
*/
TestRunnable lastRunnable = executeTestRunnables(ue, 5).get(TEST_QTY - 1);
ue.shutdown();
// runnable should finish
lastRunnable.blockTillFinished();
}
@Test
public void shutdownNowTest() {
UnfairExecutor ue = new UnfairExecutor(1);
// execute one runnable which will not complete
BlockingTestRunnable btr = new BlockingTestRunnable();
ue.execute(btr);
try {
List<TestRunnable> expectedRunnables = executeTestRunnables(ue, 0);
btr.blockTillStarted();
List<Runnable> canceledRunnables = ue.shutdownNow();
// unblock now so that others can run (if the unit test fails)
btr.unblock();
assertNotNull(canceledRunnables);
assertTrue(canceledRunnables.containsAll(expectedRunnables));
assertTrue(expectedRunnables.containsAll(canceledRunnables));
Iterator<TestRunnable> it = expectedRunnables.iterator();
while (it.hasNext()) {
assertEquals(0, it.next().getRunCount());
}
} finally {
btr.unblock();
}
}
@Test
public void awaitTerminationTest() throws InterruptedException {
UnfairExecutor ue = new UnfairExecutor(1);
/* adding a run time to have greater chances that runnable
* will be waiting to execute after shutdown call.
*/
TestRunnable lastRunnable = executeTestRunnables(ue, 5).get(TEST_QTY - 1);
ue.shutdown();
ue.awaitTermination();
// runnable should already be done
assertTrue(lastRunnable.ranOnce());
}
@Test
public void awaitTerminationWithTimeoutTest() throws InterruptedException {
UnfairExecutor ue = new UnfairExecutor(1);
/* adding a run time to have greater chances that runnable
* will be waiting to execute after shutdown call.
*/
TestRunnable lastRunnable = executeTestRunnables(ue, 5).get(TEST_QTY - 1);
ue.shutdown();
assertTrue(ue.awaitTermination(1000 * 10));
// runnable should already be done
assertTrue(lastRunnable.ranOnce());
}
@Test
public void awaitTerminationWithTimeoutExpireTest() throws InterruptedException {
UnfairExecutor ue = new UnfairExecutor(1);
executeTestRunnables(ue, 1000 * 10);
long start = Clock.accurateForwardProgressingMillis();
ue.shutdown();
assertFalse(ue.awaitTermination(DELAY_TIME));
assertTrue(Clock.accurateForwardProgressingMillis() - start >= (DELAY_TIME - ALLOWED_VARIANCE));
}
@Test (expected = RejectedExecutionException.class)
public void shutdownExecutionFail() {
UnfairExecutor ue = new UnfairExecutor(1);
ue.shutdown();
ue.execute(DoNothingRunnable.instance());
}
@Test (expected = RejectedExecutionException.class)
public void shutdownNowExecutionFail() {
UnfairExecutor ue = new UnfairExecutor(1);
ue.shutdownNow();
ue.execute(DoNothingRunnable.instance());
}
private static class UnfairExecutorFactory implements SubmitterExecutorFactory {
private List<UnfairExecutor> executors = new ArrayList<>(1);
@Override
public UnfairExecutor makeSubmitterExecutor(int poolSize, boolean prestartIfAvailable) {
UnfairExecutor result = new UnfairExecutor(poolSize);
executors.add(result);
return result;
}
@Override
public void shutdown() {
for (UnfairExecutor ue : executors) {
ue.shutdownNow();
}
}
}
}