// Copyright (c) 2007 Dustin Sallings <dustin@spy.net>
package net.spy.concurrent;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import junit.framework.TestCase;
/**
* Test the scheduled executor completion service.
*/
public class ScheduledExecutorCompletionServiceTest extends TestCase {
private ScheduledExecutorService tpe=null;
private ScheduledCompletionService<Object> scs=null;
@Override
protected void setUp() throws Exception {
super.setUp();
tpe=new Rescheduler(new ScheduledThreadPoolExecutor(2));
scs=new ScheduledExecutorCompletionService<Object>(tpe);
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
tpe.shutdown();
scs=null;
}
public void testRunnableNow() throws Exception {
Object rv=new Object();
scs.submit(new TestRunnable(), rv);
Future<Object> f=scs.take();
assertSame(rv, f.get());
}
public void testCallableNow() throws Exception {
Object rv=new Object();
scs.submit(new TestCallable(rv));
Future<Object> f=scs.take();
assertSame(rv, f.get());
}
public void testRetryableCallableNow() throws Exception {
Object rv=new Object();
scs.submit(new TestRetryableCallable(rv));
Future<Object> f=scs.take();
assertSame(rv, f.get());
}
public void testScheduledRunnable() throws Exception {
scs.schedule(new TestRunnable(), 100, TimeUnit.MILLISECONDS);
assertNull(scs.poll());
assertNull(scs.poll(10, TimeUnit.MILLISECONDS));
Future<Object> f=scs.poll(1000, TimeUnit.MILLISECONDS);
assertNull(f.get()); // This shouldn't throw an exception
}
public void testScheduledFuture() throws Exception {
Object rv=new Object();
scs.schedule(new TestCallable(rv), 100, TimeUnit.MILLISECONDS);
assertNull(scs.poll());
assertNull(scs.poll(10, TimeUnit.MILLISECONDS));
Future<Object> f=scs.take();
assertSame(rv, f.get());
}
public void testScheduledRetryableCallable() throws Exception {
Object rv=new Object();
scs.schedule(new TestRetryableCallable(rv), 100, TimeUnit.MILLISECONDS);
assertNull(scs.poll());
Future<Object> f=scs.take();
assertSame(rv, f.get());
}
public void testFailedScheduledRetryableCallable() throws Exception {
Object rv=new Object();
scs.schedule(new TestRetryableCallable(rv, 2), 100,
TimeUnit.MILLISECONDS);
assertNull(scs.poll());
Future<Object> f=scs.take();
try {
Object x=f.get();
fail("Expected failure, got " + x);
} catch(CompositeExecutorException e) {
assertEquals("Too many failures", e.getMessage());
assertEquals(2, e.getExceptions().size());
for(ExecutionException t : e.getExceptions()) {
assertEquals("Damn!", t.getCause().getMessage());
assertSame(Exception.class, t.getCause().getClass());
}
}
}
static class TestRunnable implements Runnable {
public void run() {
// look, I ran
}
}
static class TestCallable implements Callable<Object> {
private Object rv=null;
public TestCallable(Object o) {
super();
rv=o;
}
public Object call() throws Exception {
return rv;
}
}
static class TestRetryableCallable
extends TestCallable implements RetryableCallable<Object> {
int failures=0;
int maxFailures=0;
private long retryTime=10;
public TestRetryableCallable(Object o, int m) {
super(o);
maxFailures=m;
}
public TestRetryableCallable(Object o) {
this(o, 4);
}
@Override
public Object call() throws Exception {
if(failures < 3) {
failures++;
throw new Exception("Damn!");
}
return super.call();
}
public long getRetryDelay() {
return retryTime;
}
public void onComplete(boolean success, Object res) {
// OK
}
public void onExecutionException(ExecutionException exception) {
if(++failures >= maxFailures) {
retryTime=-1;
}
}
}
}