package org.oddjob.scheduling;
import java.util.List;
import java.util.concurrent.Exchanger;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
import org.apache.log4j.Logger;
public class TrackingExecutorTest extends TestCase {
private static final Logger logger = Logger.getLogger(TrackingExecutorTest.class);
@Override
protected void setUp() {
logger.debug("=============== " + getName() + " ===================");
}
class MockRunnable implements Runnable {
public void run() {
throw new RuntimeException("Unexpected.");
}
}
public void testCancel() throws InterruptedException {
MockRunnable runnable = new MockRunnable();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
TrackingExecutor test = new TrackingExecutor(executor);
ScheduledFuture<?> future = test.schedule(
runnable, 100, TimeUnit.HOURS);
assertEquals(1, test.getTaskCount());
future.cancel(true);
assertEquals(0, test.getTaskCount());
// And then again.
future.cancel(true);
assertEquals(0, test.getTaskCount());
// testing no exceptions.
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
assertTrue(executor.isTerminated());
}
class MyRunable implements Runnable {
boolean ran;
public void run() {
ran = true;
}
}
public void testCancelWhenAlreadyRun() throws InterruptedException {
MyRunable runnable = new MyRunable();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
TrackingExecutor test = new TrackingExecutor(executor);
ScheduledFuture<?> future = test.schedule(
runnable, 100, TimeUnit.MILLISECONDS);
test.waitForNothingOutstanding();
future.cancel(true);
// And then again.
future.cancel(true);
// testing no exceptions.
executor.shutdown();
executor.awaitTermination(5, TimeUnit.SECONDS);
assertTrue(executor.isTerminated());
}
class StubbonRunnable implements Runnable {
boolean interrupted;
Exchanger<Void> exchanger = new Exchanger<Void>();
public void run() {
try {
exchanger.exchange(null);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
interrupted = true;
logger.debug("Interrupted.");
try {
exchanger.exchange(null);
} catch (InterruptedException e2) {
throw new RuntimeException(e2);
}
}
}
}
public void testLongRunningCancel() throws InterruptedException {
StubbonRunnable runnable = new StubbonRunnable();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1,
new RejectedExecutionHandler() {
public void rejectedExecution(Runnable r,
ThreadPoolExecutor executor) {
fail("Unexpected.");
}
});
TrackingExecutor test = new TrackingExecutor(executor);
ScheduledFuture<?> future = test.schedule(
runnable, 0, TimeUnit.MILLISECONDS);
runnable.exchanger.exchange(null);
assertEquals(1, test.getTaskCount());
future.cancel(true);
assertEquals(0, test.getTaskCount());
// interrupt happens on different thread.
runnable.exchanger.exchange(null);
assertTrue(runnable.interrupted);
List<Runnable> outstanding = test.shutdownNow();
// guess already running.
assertEquals(0, outstanding.size());
executor.awaitTermination(5, TimeUnit.SECONDS);
assertTrue(executor.isTerminated());
}
}