--- jsr166/src/test/tck/FutureTaskTest.java 2010/09/16 00:52:49 1.20 +++ jsr166/src/test/tck/FutureTaskTest.java 2011/03/15 19:47:06 1.24 @@ -1,7 +1,7 @@ /* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at - * http://creativecommons.org/licenses/publicdomain + * http://creativecommons.org/publicdomain/zero/1.0/ * Other contributors include Andrew Wright, Jeffrey Hayes, * Pat Fisher, Mike Judd. */ @@ -9,6 +9,7 @@ import junit.framework.*; import java.util.concurrent.*; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.SECONDS; import java.util.*; public class FutureTaskTest extends JSR166TestCase { @@ -20,6 +21,68 @@ public class FutureTaskTest extends JSR1 return new TestSuite(FutureTaskTest.class); } + void checkNotDone(Future f) { + assertFalse(f.isDone()); + assertFalse(f.isCancelled()); + } + + void checkCompletedNormally(Future f, T expected) { + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + + try { + assertSame(expected, f.get()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + try { + assertSame(expected, f.get(5L, SECONDS)); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + assertFalse(f.cancel(false)); + assertFalse(f.cancel(true)); + } + + void checkCancelled(Future f) { + assertTrue(f.isDone()); + assertTrue(f.isCancelled()); + + try { + f.get(); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (CancellationException success) { + } catch (Throwable fail) { threadUnexpectedException(fail); } + + assertFalse(f.cancel(false)); + assertFalse(f.cancel(true)); + } + + void checkCompletedAbnormally(Future f, Throwable t) { + assertTrue(f.isDone()); + assertFalse(f.isCancelled()); + + try { + f.get(); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + try { + f.get(5L, SECONDS); + shouldThrow(); + } catch (ExecutionException success) { + assertSame(t, success.getCause()); + } catch (Throwable fail) { threadUnexpectedException(fail); } + + assertFalse(f.cancel(false)); + assertFalse(f.cancel(true)); + } + /** * Subclass to expose protected methods */ @@ -57,7 +120,7 @@ public class FutureTaskTest extends JSR1 FutureTask task = new FutureTask(new NoOpCallable()); task.run(); assertTrue(task.isDone()); - assertFalse(task.isCancelled()); + checkCompletedNormally(task, Boolean.TRUE); } /** @@ -66,7 +129,7 @@ public class FutureTaskTest extends JSR1 public void testRunAndReset() { PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); assertTrue(task.runAndReset()); - assertFalse(task.isDone()); + checkNotDone(task); } /** @@ -76,12 +139,10 @@ public class FutureTaskTest extends JSR1 PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); assertTrue(task.cancel(false)); assertFalse(task.runAndReset()); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); + checkCancelled(task); } - /** * setting value causes get to return it */ @@ -89,6 +150,7 @@ public class FutureTaskTest extends JSR1 PublicFutureTask task = new PublicFutureTask(new NoOpCallable()); task.set(one); assertSame(task.get(), one); + checkCompletedNormally(task, one); } /** @@ -103,18 +165,18 @@ public class FutureTaskTest extends JSR1 shouldThrow(); } catch (ExecutionException success) { assertSame(success.getCause(), nse); + checkCompletedAbnormally(task, nse); } } /** - * Cancelling before running succeeds + * Cancelling before running succeeds */ public void testCancelBeforeRun() { FutureTask task = new FutureTask(new NoOpCallable()); assertTrue(task.cancel(false)); task.run(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); + checkCancelled(task); } /** @@ -124,8 +186,7 @@ public class FutureTaskTest extends JSR1 FutureTask task = new FutureTask(new NoOpCallable()); assertTrue(task.cancel(true)); task.run(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); + checkCancelled(task); } /** @@ -135,122 +196,193 @@ public class FutureTaskTest extends JSR1 FutureTask task = new FutureTask(new NoOpCallable()); task.run(); assertFalse(task.cancel(false)); - assertTrue(task.isDone()); - assertFalse(task.isCancelled()); + checkCompletedNormally(task, Boolean.TRUE); } /** * cancel(true) interrupts a running task */ public void testCancelInterrupt() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); final FutureTask task = - new FutureTask(new CheckedInterruptedCallable() { - public Object realCall() throws InterruptedException { - Thread.sleep(SMALL_DELAY_MS); - return Boolean.TRUE; + new FutureTask(new CheckedCallable() { + public Object realCall() { + threadStarted.countDown(); + long t0 = System.nanoTime(); + for (;;) { + if (Thread.interrupted()) + return Boolean.TRUE; + if (millisElapsedSince(t0) > MEDIUM_DELAY_MS) + fail("interrupt not delivered"); + Thread.yield(); + } }}); - Thread t = new Thread(task); - t.start(); - Thread.sleep(SHORT_DELAY_MS); + Thread t = newStartedThread(task); + threadStarted.await(); assertTrue(task.cancel(true)); - t.join(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); + checkCancelled(task); + awaitTermination(t, MEDIUM_DELAY_MS); + checkCancelled(task); } - /** * cancel(false) does not interrupt a running task */ public void testCancelNoInterrupt() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + final CountDownLatch cancelled = new CountDownLatch(1); + final FutureTask task = + new FutureTask(new CheckedCallable() { + public Boolean realCall() throws InterruptedException { + threadStarted.countDown(); + cancelled.await(MEDIUM_DELAY_MS, MILLISECONDS); + assertFalse(Thread.interrupted()); + return Boolean.TRUE; + }}); + + Thread t = newStartedThread(task); + threadStarted.await(); + assertTrue(task.cancel(false)); + checkCancelled(task); + cancelled.countDown(); + awaitTermination(t, MEDIUM_DELAY_MS); + checkCancelled(task); + } + + /** + * run in one thread causes get in another thread to retrieve value + */ + public void testGetRun() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + final FutureTask task = new FutureTask(new CheckedCallable() { public Object realCall() throws InterruptedException { - Thread.sleep(MEDIUM_DELAY_MS); return Boolean.TRUE; }}); - Thread t = new Thread(task); - t.start(); - Thread.sleep(SHORT_DELAY_MS); - assertTrue(task.cancel(false)); - t.join(); - assertTrue(task.isDone()); - assertTrue(task.isCancelled()); + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + threadStarted.countDown(); + assertSame(Boolean.TRUE, task.get()); + }}); + + threadStarted.await(); + checkNotDone(task); + assertTrue(t.isAlive()); + task.run(); + checkCompletedNormally(task, Boolean.TRUE); + awaitTermination(t, MEDIUM_DELAY_MS); } /** * set in one thread causes get in another thread to retrieve value */ - public void testGet1() throws InterruptedException { - final FutureTask ft = + public void testGetSet() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + + final PublicFutureTask task = + new PublicFutureTask(new CheckedCallable() { + public Object realCall() throws InterruptedException { + return Boolean.TRUE; + }}); + + Thread t = newStartedThread(new CheckedRunnable() { + public void realRun() throws Exception { + threadStarted.countDown(); + assertSame(Boolean.FALSE, task.get()); + }}); + + threadStarted.await(); + checkNotDone(task); + assertTrue(t.isAlive()); + task.set(Boolean.FALSE); + checkCompletedNormally(task, Boolean.FALSE); + awaitTermination(t, MEDIUM_DELAY_MS); + } + + /** + * run in one thread causes timed get in another thread to retrieve value + */ + public void testTimedGetRun() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + + final FutureTask task = new FutureTask(new CheckedCallable() { public Object realCall() throws InterruptedException { return Boolean.TRUE; }}); - Thread t = new Thread(new CheckedRunnable() { + + Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws Exception { - assertSame(Boolean.TRUE, ft.get()); + threadStarted.countDown(); + assertSame(Boolean.TRUE, + task.get(MEDIUM_DELAY_MS, MILLISECONDS)); }}); - assertFalse(ft.isDone()); - assertFalse(ft.isCancelled()); - t.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.run(); - t.join(); - assertTrue(ft.isDone()); - assertFalse(ft.isCancelled()); + threadStarted.await(); + checkNotDone(task); + assertTrue(t.isAlive()); + task.run(); + checkCompletedNormally(task, Boolean.TRUE); + awaitTermination(t, MEDIUM_DELAY_MS); } /** * set in one thread causes timed get in another thread to retrieve value */ - public void testTimedGet1() throws InterruptedException { - final FutureTask ft = - new FutureTask(new CheckedCallable() { + public void testTimedGetSet() throws InterruptedException { + final CountDownLatch threadStarted = new CountDownLatch(1); + + final PublicFutureTask task = + new PublicFutureTask(new CheckedCallable() { public Object realCall() throws InterruptedException { return Boolean.TRUE; }}); - Thread t = new Thread(new CheckedRunnable() { + + Thread t = newStartedThread(new CheckedRunnable() { public void realRun() throws Exception { - assertSame(Boolean.TRUE, ft.get(SMALL_DELAY_MS, MILLISECONDS)); + threadStarted.countDown(); + assertSame(Boolean.FALSE, + task.get(MEDIUM_DELAY_MS, MILLISECONDS)); }}); - assertFalse(ft.isDone()); - assertFalse(ft.isCancelled()); - t.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.run(); - t.join(); - assertTrue(ft.isDone()); - assertFalse(ft.isCancelled()); + threadStarted.await(); + checkNotDone(task); + assertTrue(t.isAlive()); + task.set(Boolean.FALSE); + checkCompletedNormally(task, Boolean.FALSE); + awaitTermination(t, MEDIUM_DELAY_MS); } /** - * Cancelling a task causes timed get in another thread to throw - * CancellationException + * Cancelling a task causes timed get in another thread to throw + * CancellationException */ public void testTimedGet_Cancellation() throws InterruptedException { - final FutureTask ft = + final CountDownLatch threadStarted = new CountDownLatch(2); + final FutureTask task = new FutureTask(new CheckedInterruptedCallable() { public Object realCall() throws InterruptedException { - Thread.sleep(SMALL_DELAY_MS); + threadStarted.countDown(); + Thread.sleep(LONG_DELAY_MS); return Boolean.TRUE; }}); Thread t1 = new ThreadShouldThrow(CancellationException.class) { public void realRun() throws Exception { - ft.get(MEDIUM_DELAY_MS, MILLISECONDS); + threadStarted.countDown(); + task.get(MEDIUM_DELAY_MS, MILLISECONDS); }}; - Thread t2 = new Thread(ft); + Thread t2 = new Thread(task); t1.start(); t2.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.cancel(true); - t1.join(); - t2.join(); + threadStarted.await(); + task.cancel(true); + awaitTermination(t1, MEDIUM_DELAY_MS); + awaitTermination(t2, MEDIUM_DELAY_MS); + checkCancelled(task); } /** @@ -258,24 +390,28 @@ public class FutureTaskTest extends JSR1 * CancellationException */ public void testGet_Cancellation() throws InterruptedException { - final FutureTask ft = + final CountDownLatch threadStarted = new CountDownLatch(2); + final FutureTask task = new FutureTask(new CheckedInterruptedCallable() { public Object realCall() throws InterruptedException { - Thread.sleep(SMALL_DELAY_MS); + threadStarted.countDown(); + Thread.sleep(LONG_DELAY_MS); return Boolean.TRUE; }}); + Thread t1 = new ThreadShouldThrow(CancellationException.class) { public void realRun() throws Exception { - ft.get(); + threadStarted.countDown(); + task.get(); }}; - - Thread t2 = new Thread(ft); + Thread t2 = new Thread(task); t1.start(); t2.start(); - Thread.sleep(SHORT_DELAY_MS); - ft.cancel(true); - t1.join(); - t2.join(); + threadStarted.await(); + task.cancel(true); + awaitTermination(t1, MEDIUM_DELAY_MS); + awaitTermination(t2, MEDIUM_DELAY_MS); + checkCancelled(task); } @@ -283,17 +419,18 @@ public class FutureTaskTest extends JSR1 * A runtime exception in task causes get to throw ExecutionException */ public void testGet_ExecutionException() throws InterruptedException { - final FutureTask ft = new FutureTask(new Callable() { + final FutureTask task = new FutureTask(new Callable() { public Object call() { return 5/0; }}); - ft.run(); + task.run(); try { - ft.get(); + task.get(); shouldThrow(); } catch (ExecutionException success) { assertTrue(success.getCause() instanceof ArithmeticException); + checkCompletedAbnormally(task, success.getCause()); } } @@ -301,17 +438,18 @@ public class FutureTaskTest extends JSR1 * A runtime exception in task causes timed get to throw ExecutionException */ public void testTimedGet_ExecutionException2() throws Exception { - final FutureTask ft = new FutureTask(new Callable() { + final FutureTask task = new FutureTask(new Callable() { public Object call() { return 5/0; }}); - ft.run(); + task.run(); try { - ft.get(SHORT_DELAY_MS, MILLISECONDS); + task.get(SHORT_DELAY_MS, MILLISECONDS); shouldThrow(); } catch (ExecutionException success) { assertTrue(success.getCause() instanceof ArithmeticException); + checkCompletedAbnormally(task, success.getCause()); } } @@ -320,32 +458,36 @@ public class FutureTaskTest extends JSR1 * Interrupting a waiting get causes it to throw InterruptedException */ public void testGet_InterruptedException() throws InterruptedException { - final FutureTask ft = new FutureTask(new NoOpCallable()); - Thread t = new Thread(new CheckedInterruptedRunnable() { + final CountDownLatch threadStarted = new CountDownLatch(1); + final FutureTask task = new FutureTask(new NoOpCallable()); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { public void realRun() throws Exception { - ft.get(); + threadStarted.countDown(); + task.get(); }}); - t.start(); - Thread.sleep(SHORT_DELAY_MS); + threadStarted.await(); t.interrupt(); - t.join(); + awaitTermination(t, MEDIUM_DELAY_MS); + checkNotDone(task); } /** * Interrupting a waiting timed get causes it to throw InterruptedException */ public void testTimedGet_InterruptedException2() throws InterruptedException { - final FutureTask ft = new FutureTask(new NoOpCallable()); - Thread t = new Thread(new CheckedInterruptedRunnable() { + final CountDownLatch threadStarted = new CountDownLatch(1); + final FutureTask task = new FutureTask(new NoOpCallable()); + Thread t = newStartedThread(new CheckedInterruptedRunnable() { public void realRun() throws Exception { - ft.get(LONG_DELAY_MS,MILLISECONDS); + threadStarted.countDown(); + task.get(LONG_DELAY_MS, MILLISECONDS); }}); - t.start(); - Thread.sleep(SHORT_DELAY_MS); + threadStarted.await(); t.interrupt(); - t.join(); + awaitTermination(t, MEDIUM_DELAY_MS); + checkNotDone(task); } /** @@ -353,8 +495,8 @@ public class FutureTaskTest extends JSR1 */ public void testGet_TimeoutException() throws Exception { try { - FutureTask ft = new FutureTask(new NoOpCallable()); - ft.get(1,MILLISECONDS); + FutureTask task = new FutureTask(new NoOpCallable()); + task.get(1, MILLISECONDS); shouldThrow(); } catch (TimeoutException success) {} }