--- jsr166/src/test/tck/JSR166TestCase.java 2010/10/06 07:49:22 1.60 +++ jsr166/src/test/tck/JSR166TestCase.java 2011/05/21 06:24:33 1.81 @@ -1,16 +1,25 @@ /* * 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. */ import junit.framework.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Arrays; +import java.util.Date; +import java.util.NoSuchElementException; import java.util.PropertyPermission; import java.util.concurrent.*; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static java.util.concurrent.TimeUnit.NANOSECONDS; import java.security.CodeSource; import java.security.Permission; import java.security.PermissionCollection; @@ -96,6 +105,42 @@ public class JSR166TestCase extends Test private static final boolean useSecurityManager = Boolean.getBoolean("jsr166.useSecurityManager"); + protected static final boolean expensiveTests = + Boolean.getBoolean("jsr166.expensiveTests"); + + /** + * If true, report on stdout all "slow" tests, that is, ones that + * take more than profileThreshold milliseconds to execute. + */ + private static final boolean profileTests = + Boolean.getBoolean("jsr166.profileTests"); + + /** + * The number of milliseconds that tests are permitted for + * execution without being reported, when profileTests is set. + */ + private static final long profileThreshold = + Long.getLong("jsr166.profileThreshold", 100); + + protected void runTest() throws Throwable { + if (profileTests) + runTestProfiled(); + else + super.runTest(); + } + + protected void runTestProfiled() throws Throwable { + long t0 = System.nanoTime(); + try { + super.runTest(); + } finally { + long elapsedMillis = + (System.nanoTime() - t0) / (1000L * 1000L); + if (elapsedMillis >= profileThreshold) + System.out.printf("%n%s: %d%n", toString(), elapsedMillis); + } + } + /** * Runs all JSR166 unit tests using junit.textui.TestRunner */ @@ -223,7 +268,23 @@ public class JSR166TestCase extends Test SHORT_DELAY_MS = getShortDelay(); SMALL_DELAY_MS = SHORT_DELAY_MS * 5; MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10; - LONG_DELAY_MS = SHORT_DELAY_MS * 50; + LONG_DELAY_MS = SHORT_DELAY_MS * 200; + } + + /** + * Returns a timeout in milliseconds to be used in tests that + * verify that operations block or time out. + */ + long timeoutMillis() { + return SHORT_DELAY_MS / 4; + } + + /** + * Returns a new Date instance representing a time delayMillis + * milliseconds in the future. + */ + Date delayedDate(long delayMillis) { + return new Date(new Date().getTime() + delayMillis); } /** @@ -252,7 +313,7 @@ public class JSR166TestCase extends Test * earlier by threadRecordFailure. */ public void tearDown() throws Exception { - Throwable t = threadFailure.get(); + Throwable t = threadFailure.getAndSet(null); if (t != null) { if (t instanceof Error) throw (Error) t; @@ -404,13 +465,34 @@ public class JSR166TestCase extends Test } /** + * Delays, via Thread.sleep, for the given millisecond delay, but + * if the sleep is shorter than specified, may re-sleep or yield + * until time elapses. + */ + static void delay(long millis) throws InterruptedException { + long startTime = System.nanoTime(); + long ns = millis * 1000 * 1000; + for (;;) { + if (millis > 0L) + Thread.sleep(millis); + else // too short to sleep + Thread.yield(); + long d = ns - (System.nanoTime() - startTime); + if (d > 0L) + millis = d / (1000 * 1000); + else + break; + } + } + + /** * Waits out termination of a thread pool or fails doing so. */ - public void joinPool(ExecutorService exec) { + void joinPool(ExecutorService exec) { try { exec.shutdown(); assertTrue("ExecutorService did not terminate in a timely manner", - exec.awaitTermination(LONG_DELAY_MS, MILLISECONDS)); + exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS)); } catch (SecurityException ok) { // Allowed in case test doesn't have privs } catch (InterruptedException ie) { @@ -418,6 +500,26 @@ public class JSR166TestCase extends Test } } + /** + * Checks that thread does not terminate within the default + * millisecond delay of {@code timeoutMillis()}. + */ + void assertThreadStaysAlive(Thread thread) { + assertThreadStaysAlive(thread, timeoutMillis()); + } + + /** + * Checks that thread does not terminate within the given millisecond delay. + */ + void assertThreadStaysAlive(Thread thread, long millis) { + try { + // No need to optimize the failing case via Thread.join. + delay(millis); + assertTrue(thread.isAlive()); + } catch (InterruptedException ie) { + fail("Unexpected InterruptedException"); + } + } /** * Fails with message "should throw exception". @@ -549,7 +651,7 @@ public class JSR166TestCase extends Test */ void sleep(long millis) { try { - Thread.sleep(millis); + delay(millis); } catch (InterruptedException ie) { AssertionFailedError afe = new AssertionFailedError("Unexpected InterruptedException"); @@ -559,13 +661,43 @@ public class JSR166TestCase extends Test } /** - * Sleeps until the timeout has elapsed, or interrupted. - * Does NOT throw InterruptedException. + * Waits up to the specified number of milliseconds for the given + * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING. */ - void sleepTillInterrupted(long timeoutMillis) { - try { - Thread.sleep(timeoutMillis); - } catch (InterruptedException wakeup) {} + void waitForThreadToEnterWaitState(Thread thread, long timeoutMillis) { + long timeoutNanos = timeoutMillis * 1000L * 1000L; + long t0 = System.nanoTime(); + for (;;) { + Thread.State s = thread.getState(); + if (s == Thread.State.BLOCKED || + s == Thread.State.WAITING || + s == Thread.State.TIMED_WAITING) + return; + else if (s == Thread.State.TERMINATED) + fail("Unexpected thread termination"); + else if (System.nanoTime() - t0 > timeoutNanos) { + threadAssertTrue(thread.isAlive()); + return; + } + Thread.yield(); + } + } + + /** + * Waits up to LONG_DELAY_MS for the given thread to enter a wait + * state: BLOCKED, WAITING, or TIMED_WAITING. + */ + void waitForThreadToEnterWaitState(Thread thread) { + waitForThreadToEnterWaitState(thread, LONG_DELAY_MS); + } + + /** + * Returns the number of milliseconds since time given by + * startNanoTime, which must have been previously returned from a + * call to {@link System.nanoTime()}. + */ + long millisElapsedSince(long startNanoTime) { + return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime); } /** @@ -596,6 +728,15 @@ public class JSR166TestCase extends Test } } + /** + * Waits for LONG_DELAY_MS milliseconds for the thread to + * terminate (using {@link Thread#join(long)}), else interrupts + * the thread (in the hope that it may terminate later) and fails. + */ + void awaitTermination(Thread t) { + awaitTermination(t, LONG_DELAY_MS); + } + // Some convenient Runnable classes public abstract class CheckedRunnable implements Runnable { @@ -658,6 +799,7 @@ public class JSR166TestCase extends Test realRun(); threadShouldThrow("InterruptedException"); } catch (InterruptedException success) { + threadAssertFalse(Thread.interrupted()); } catch (Throwable t) { threadUnexpectedException(t); } @@ -687,6 +829,7 @@ public class JSR166TestCase extends Test threadShouldThrow("InterruptedException"); return result; } catch (InterruptedException success) { + threadAssertFalse(Thread.interrupted()); } catch (Throwable t) { threadUnexpectedException(t); } @@ -710,7 +853,7 @@ public class JSR166TestCase extends Test public Callable latchAwaitingStringTask(final CountDownLatch latch) { return new CheckedCallable() { - public String realCall() { + protected String realCall() { try { latch.await(); } catch (InterruptedException quittingTime) {} @@ -718,6 +861,40 @@ public class JSR166TestCase extends Test }}; } + public Runnable awaiter(final CountDownLatch latch) { + return new CheckedRunnable() { + public void realRun() throws InterruptedException { + await(latch); + }}; + } + + public void await(CountDownLatch latch) { + try { + assertTrue(latch.await(LONG_DELAY_MS, MILLISECONDS)); + } catch (Throwable t) { + threadUnexpectedException(t); + } + } + +// /** +// * Spin-waits up to LONG_DELAY_MS until flag becomes true. +// */ +// public void await(AtomicBoolean flag) { +// await(flag, LONG_DELAY_MS); +// } + +// /** +// * Spin-waits up to the specified timeout until flag becomes true. +// */ +// public void await(AtomicBoolean flag, long timeoutMillis) { +// long startTime = System.nanoTime(); +// while (!flag.get()) { +// if (millisElapsedSince(startTime) > timeoutMillis) +// throw new AssertionFailedError("timed out"); +// Thread.yield(); +// } +// } + public static class NPETask implements Callable { public String call() { throw new NullPointerException(); } } @@ -728,53 +905,62 @@ public class JSR166TestCase extends Test public class ShortRunnable extends CheckedRunnable { protected void realRun() throws Throwable { - Thread.sleep(SHORT_DELAY_MS); + delay(SHORT_DELAY_MS); } } public class ShortInterruptedRunnable extends CheckedInterruptedRunnable { protected void realRun() throws InterruptedException { - Thread.sleep(SHORT_DELAY_MS); + delay(SHORT_DELAY_MS); } } public class SmallRunnable extends CheckedRunnable { protected void realRun() throws Throwable { - Thread.sleep(SMALL_DELAY_MS); + delay(SMALL_DELAY_MS); } } public class SmallPossiblyInterruptedRunnable extends CheckedRunnable { protected void realRun() { try { - Thread.sleep(SMALL_DELAY_MS); + delay(SMALL_DELAY_MS); } catch (InterruptedException ok) {} } } public class SmallCallable extends CheckedCallable { protected Object realCall() throws InterruptedException { - Thread.sleep(SMALL_DELAY_MS); + delay(SMALL_DELAY_MS); return Boolean.TRUE; } } public class MediumRunnable extends CheckedRunnable { protected void realRun() throws Throwable { - Thread.sleep(MEDIUM_DELAY_MS); + delay(MEDIUM_DELAY_MS); } } public class MediumInterruptedRunnable extends CheckedInterruptedRunnable { protected void realRun() throws InterruptedException { - Thread.sleep(MEDIUM_DELAY_MS); + delay(MEDIUM_DELAY_MS); } } + public Runnable possiblyInterruptedRunnable(final long timeoutMillis) { + return new CheckedRunnable() { + protected void realRun() { + try { + delay(timeoutMillis); + } catch (InterruptedException ok) {} + }}; + } + public class MediumPossiblyInterruptedRunnable extends CheckedRunnable { protected void realRun() { try { - Thread.sleep(MEDIUM_DELAY_MS); + delay(MEDIUM_DELAY_MS); } catch (InterruptedException ok) {} } } @@ -782,7 +968,7 @@ public class JSR166TestCase extends Test public class LongPossiblyInterruptedRunnable extends CheckedRunnable { protected void realRun() { try { - Thread.sleep(LONG_DELAY_MS); + delay(LONG_DELAY_MS); } catch (InterruptedException ok) {} } } @@ -796,11 +982,38 @@ public class JSR166TestCase extends Test } } + public interface TrackedRunnable extends Runnable { + boolean isDone(); + } + + public static TrackedRunnable trackedRunnable(final long timeoutMillis) { + return new TrackedRunnable() { + private volatile boolean done = false; + public boolean isDone() { return done; } + public void run() { + try { + delay(timeoutMillis); + done = true; + } catch (InterruptedException ok) {} + } + }; + } + public static class TrackedShortRunnable implements Runnable { public volatile boolean done = false; public void run() { try { - Thread.sleep(SMALL_DELAY_MS); + delay(SHORT_DELAY_MS); + done = true; + } catch (InterruptedException ok) {} + } + } + + public static class TrackedSmallRunnable implements Runnable { + public volatile boolean done = false; + public void run() { + try { + delay(SMALL_DELAY_MS); done = true; } catch (InterruptedException ok) {} } @@ -810,7 +1023,7 @@ public class JSR166TestCase extends Test public volatile boolean done = false; public void run() { try { - Thread.sleep(MEDIUM_DELAY_MS); + delay(MEDIUM_DELAY_MS); done = true; } catch (InterruptedException ok) {} } @@ -820,7 +1033,7 @@ public class JSR166TestCase extends Test public volatile boolean done = false; public void run() { try { - Thread.sleep(LONG_DELAY_MS); + delay(LONG_DELAY_MS); done = true; } catch (InterruptedException ok) {} } @@ -837,7 +1050,7 @@ public class JSR166TestCase extends Test public volatile boolean done = false; public Object call() { try { - Thread.sleep(SMALL_DELAY_MS); + delay(SMALL_DELAY_MS); done = true; } catch (InterruptedException ok) {} return Boolean.TRUE; @@ -902,4 +1115,48 @@ public class JSR166TestCase extends Test } } + void checkEmpty(BlockingQueue q) { + try { + assertTrue(q.isEmpty()); + assertEquals(0, q.size()); + assertNull(q.peek()); + assertNull(q.poll()); + assertNull(q.poll(0, MILLISECONDS)); + assertEquals(q.toString(), "[]"); + assertTrue(Arrays.equals(q.toArray(), new Object[0])); + assertFalse(q.iterator().hasNext()); + try { + q.element(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + q.iterator().next(); + shouldThrow(); + } catch (NoSuchElementException success) {} + try { + q.remove(); + shouldThrow(); + } catch (NoSuchElementException success) {} + } catch (InterruptedException ie) { + threadUnexpectedException(ie); + } + } + + @SuppressWarnings("unchecked") + T serialClone(T o) { + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(o); + oos.flush(); + oos.close(); + ByteArrayInputStream bin = + new ByteArrayInputStream(bos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bin); + return (T) ois.readObject(); + } catch (Throwable t) { + threadUnexpectedException(t); + return null; + } + } }