--- jsr166/src/test/tck/JSR166TestCase.java 2018/11/24 21:48:19 1.250
+++ jsr166/src/test/tck/JSR166TestCase.java 2021/01/26 13:33:06 1.272
@@ -49,6 +49,7 @@ import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.management.ManagementFactory;
+import java.lang.management.LockInfo;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
import java.lang.reflect.Constructor;
@@ -73,6 +74,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.PropertyPermission;
+import java.util.Queue;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
@@ -149,6 +151,11 @@ import junit.framework.TestSuite;
* but even so, if there is ever any doubt, they can all be increased
* in one spot to rerun tests on slower platforms.
*
+ * Class Item is used for elements of collections and related
+ * purposes. Many tests rely on themir keys being equal to ints. To
+ * check these, methods mustEqual, mustContain, etc adapt the JUnit
+ * assert methods to intercept ints.
+ *
*
All threads generated must be joined inside each test case
* method (or {@code fail} to do so) before returning from the
* method. The {@code joinPool} method can be used to do this when
@@ -243,6 +250,9 @@ public class JSR166TestCase extends Test
}
}
+ private static final ThreadMXBean THREAD_MXBEAN
+ = ManagementFactory.getThreadMXBean();
+
/**
* The scaling factor to apply to standard delays used in tests.
* May be initialized from any of:
@@ -284,12 +294,13 @@ public class JSR166TestCase extends Test
static volatile TestCase currentTestCase;
// static volatile int currentRun = 0;
static {
- Runnable checkForWedgedTest = new Runnable() { public void run() {
+ Runnable wedgedTestDetector = new Runnable() { public void run() {
// Avoid spurious reports with enormous runsPerTest.
// A single test case run should never take more than 1 second.
// But let's cap it at the high end too ...
- final int timeoutMinutes =
- Math.min(15, Math.max(runsPerTest / 60, 1));
+ final int timeoutMinutesMin = Math.max(runsPerTest / 60, 1)
+ * Math.max((int) delayFactor, 1);
+ final int timeoutMinutes = Math.min(15, timeoutMinutesMin);
for (TestCase lastTestCase = currentTestCase;;) {
try { MINUTES.sleep(timeoutMinutes); }
catch (InterruptedException unexpected) { break; }
@@ -309,7 +320,7 @@ public class JSR166TestCase extends Test
}
lastTestCase = currentTestCase;
}}};
- Thread thread = new Thread(checkForWedgedTest, "checkForWedgedTest");
+ Thread thread = new Thread(wedgedTestDetector, "WedgedTestDetector");
thread.setDaemon(true);
thread.start();
}
@@ -353,7 +364,7 @@ public class JSR166TestCase extends Test
// Never report first run of any test; treat it as a
// warmup run, notably to trigger all needed classloading,
if (i > 0)
- System.out.printf("%n%s: %d%n", toString(), elapsedMillis);
+ System.out.printf("%s: %d%n", toString(), elapsedMillis);
}
}
@@ -460,6 +471,12 @@ public class JSR166TestCase extends Test
public static boolean atLeastJava9() { return JAVA_CLASS_VERSION >= 53.0; }
public static boolean atLeastJava10() { return JAVA_CLASS_VERSION >= 54.0; }
public static boolean atLeastJava11() { return JAVA_CLASS_VERSION >= 55.0; }
+ public static boolean atLeastJava12() { return JAVA_CLASS_VERSION >= 56.0; }
+ public static boolean atLeastJava13() { return JAVA_CLASS_VERSION >= 57.0; }
+ public static boolean atLeastJava14() { return JAVA_CLASS_VERSION >= 58.0; }
+ public static boolean atLeastJava15() { return JAVA_CLASS_VERSION >= 59.0; }
+ public static boolean atLeastJava16() { return JAVA_CLASS_VERSION >= 60.0; }
+ public static boolean atLeastJava17() { return JAVA_CLASS_VERSION >= 61.0; }
/**
* Collects all JSR166 unit tests as one suite.
@@ -511,6 +528,7 @@ public class JSR166TestCase extends Test
ExecutorsTest.suite(),
ExecutorCompletionServiceTest.suite(),
FutureTaskTest.suite(),
+ HashtableTest.suite(),
LinkedBlockingDequeTest.suite(),
LinkedBlockingQueueTest.suite(),
LinkedListTest.suite(),
@@ -550,6 +568,7 @@ public class JSR166TestCase extends Test
"HashMapTest",
"LinkedBlockingDeque8Test",
"LinkedBlockingQueue8Test",
+ "LinkedHashMapTest",
"LongAccumulatorTest",
"LongAdderTest",
"SplittableRandomTest",
@@ -648,6 +667,12 @@ public class JSR166TestCase extends Test
public static long MEDIUM_DELAY_MS;
public static long LONG_DELAY_MS;
+ /**
+ * A delay significantly longer than LONG_DELAY_MS.
+ * Use this in a thread that is waited for via awaitTermination(Thread).
+ */
+ public static long LONGER_DELAY_MS;
+
private static final long RANDOM_TIMEOUT;
private static final long RANDOM_EXPIRED_TIMEOUT;
private static final TimeUnit RANDOM_TIMEUNIT;
@@ -676,6 +701,28 @@ public class JSR166TestCase extends Test
static TimeUnit randomTimeUnit() { return RANDOM_TIMEUNIT; }
/**
+ * Returns a random boolean; a "coin flip".
+ */
+ static boolean randomBoolean() {
+ return ThreadLocalRandom.current().nextBoolean();
+ }
+
+ /**
+ * Returns a random element from given choices.
+ */
+ T chooseRandomly(List choices) {
+ return choices.get(ThreadLocalRandom.current().nextInt(choices.size()));
+ }
+
+ /**
+ * Returns a random element from given choices.
+ */
+ @SuppressWarnings("unchecked")
+ T chooseRandomly(T... choices) {
+ return choices[ThreadLocalRandom.current().nextInt(choices.length)];
+ }
+
+ /**
* Returns the shortest timed delay. This can be scaled up for
* slow machines using the jsr166.delay.factor system property,
* or via jtreg's -timeoutFactor: flag.
@@ -693,6 +740,7 @@ public class JSR166TestCase extends Test
SMALL_DELAY_MS = SHORT_DELAY_MS * 5;
MEDIUM_DELAY_MS = SHORT_DELAY_MS * 10;
LONG_DELAY_MS = SHORT_DELAY_MS * 200;
+ LONGER_DELAY_MS = 2 * LONG_DELAY_MS;
}
private static final long TIMEOUT_DELAY_MS
@@ -731,8 +779,8 @@ public class JSR166TestCase extends Test
*/
public void threadRecordFailure(Throwable t) {
System.err.println(t);
- dumpTestThreads();
- threadFailure.compareAndSet(null, t);
+ if (threadFailure.compareAndSet(null, t))
+ dumpTestThreads();
}
public void setUp() {
@@ -1053,6 +1101,39 @@ public class JSR166TestCase extends Test
}
}
+ /** Returns true if thread info might be useful in a thread dump. */
+ static boolean threadOfInterest(ThreadInfo info) {
+ final String name = info.getThreadName();
+ String lockName;
+ if (name == null)
+ return true;
+ if (name.equals("Signal Dispatcher")
+ || name.equals("WedgedTestDetector"))
+ return false;
+ if (name.equals("Reference Handler")) {
+ // Reference Handler stacktrace changed in JDK-8156500
+ StackTraceElement[] stackTrace; String methodName;
+ if ((stackTrace = info.getStackTrace()) != null
+ && stackTrace.length > 0
+ && (methodName = stackTrace[0].getMethodName()) != null
+ && methodName.equals("waitForReferencePendingList"))
+ return false;
+ // jdk8 Reference Handler stacktrace
+ if ((lockName = info.getLockName()) != null
+ && lockName.startsWith("java.lang.ref"))
+ return false;
+ }
+ if ((name.equals("Finalizer") || name.equals("Common-Cleaner"))
+ && (lockName = info.getLockName()) != null
+ && lockName.startsWith("java.lang.ref"))
+ return false;
+ if (name.startsWith("ForkJoinPool.commonPool-worker")
+ && (lockName = info.getLockName()) != null
+ && lockName.startsWith("java.util.concurrent.ForkJoinPool"))
+ return false;
+ return true;
+ }
+
/**
* A debugging tool to print stack traces of most threads, as jstack does.
* Uninteresting threads are filtered out.
@@ -1067,25 +1148,10 @@ public class JSR166TestCase extends Test
}
}
- ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
System.err.println("------ stacktrace dump start ------");
- for (ThreadInfo info : threadMXBean.dumpAllThreads(true, true)) {
- final String name = info.getThreadName();
- String lockName;
- if ("Signal Dispatcher".equals(name))
- continue;
- if ("Reference Handler".equals(name)
- && (lockName = info.getLockName()) != null
- && lockName.startsWith("java.lang.ref.Reference$Lock"))
- continue;
- if ("Finalizer".equals(name)
- && (lockName = info.getLockName()) != null
- && lockName.startsWith("java.lang.ref.ReferenceQueue$Lock"))
- continue;
- if ("checkForWedgedTest".equals(name))
- continue;
- System.err.print(info);
- }
+ for (ThreadInfo info : THREAD_MXBEAN.dumpAllThreads(true, true))
+ if (threadOfInterest(info))
+ System.err.print(info);
System.err.println("------ stacktrace dump end ------");
if (sm != null) System.setSecurityManager(sm);
@@ -1112,17 +1178,28 @@ public class JSR166TestCase extends Test
}
/**
+ * Returns the thread's blocker's class name, if any, else null.
+ */
+ String blockerClassName(Thread thread) {
+ ThreadInfo threadInfo; LockInfo lockInfo;
+ if ((threadInfo = THREAD_MXBEAN.getThreadInfo(thread.getId(), 0)) != null
+ && (lockInfo = threadInfo.getLockInfo()) != null)
+ return lockInfo.getClassName();
+ return null;
+ }
+
+ /**
* Checks that future.get times out, with the default timeout of
* {@code timeoutMillis()}.
*/
- void assertFutureTimesOut(Future future) {
+ void assertFutureTimesOut(Future> future) {
assertFutureTimesOut(future, timeoutMillis());
}
/**
* Checks that future.get times out, with the given millisecond timeout.
*/
- void assertFutureTimesOut(Future future, long timeoutMillis) {
+ void assertFutureTimesOut(Future> future, long timeoutMillis) {
long startTime = System.nanoTime();
try {
future.get(timeoutMillis, MILLISECONDS);
@@ -1130,8 +1207,9 @@ public class JSR166TestCase extends Test
} catch (TimeoutException success) {
} catch (Exception fail) {
threadUnexpectedException(fail);
- } finally { future.cancel(true); }
+ }
assertTrue(millisElapsedSince(startTime) >= timeoutMillis);
+ assertFalse(future.isDone());
}
/**
@@ -1156,28 +1234,137 @@ public class JSR166TestCase extends Test
/**
* The number of elements to place in collections, arrays, etc.
+ * Must be at least ten;
*/
- public static final int SIZE = 20;
-
- // Some convenient Integer constants
+ public static final int SIZE = 32;
- public static final Integer zero = new Integer(0);
- public static final Integer one = new Integer(1);
- public static final Integer two = new Integer(2);
- public static final Integer three = new Integer(3);
- public static final Integer four = new Integer(4);
- public static final Integer five = new Integer(5);
- public static final Integer six = new Integer(6);
- public static final Integer seven = new Integer(7);
- public static final Integer eight = new Integer(8);
- public static final Integer nine = new Integer(9);
- public static final Integer m1 = new Integer(-1);
- public static final Integer m2 = new Integer(-2);
- public static final Integer m3 = new Integer(-3);
- public static final Integer m4 = new Integer(-4);
- public static final Integer m5 = new Integer(-5);
- public static final Integer m6 = new Integer(-6);
- public static final Integer m10 = new Integer(-10);
+ static Item[] seqItems(int size) {
+ Item[] s = new Item[size];
+ for (int i = 0; i < size; ++i)
+ s[i] = new Item(i);
+ return s;
+ }
+ static Item[] negativeSeqItems(int size) {
+ Item[] s = new Item[size];
+ for (int i = 0; i < size; ++i)
+ s[i] = new Item(-i);
+ return s;
+ }
+
+ // Many tests rely on defaultItems all being sequential nonnegative
+ public static final Item[] defaultItems = seqItems(SIZE);
+
+ static Item itemFor(int i) { // check cache for defaultItems
+ Item[] items = defaultItems;
+ return (i >= 0 && i < items.length) ? items[i] : new Item(i);
+ }
+
+ public static final Item zero = defaultItems[0];
+ public static final Item one = defaultItems[1];
+ public static final Item two = defaultItems[2];
+ public static final Item three = defaultItems[3];
+ public static final Item four = defaultItems[4];
+ public static final Item five = defaultItems[5];
+ public static final Item six = defaultItems[6];
+ public static final Item seven = defaultItems[7];
+ public static final Item eight = defaultItems[8];
+ public static final Item nine = defaultItems[9];
+ public static final Item ten = defaultItems[10];
+
+ public static final Item[] negativeItems = negativeSeqItems(SIZE);
+
+ public static final Item minusOne = negativeItems[1];
+ public static final Item minusTwo = negativeItems[2];
+ public static final Item minusThree = negativeItems[3];
+ public static final Item minusFour = negativeItems[4];
+ public static final Item minusFive = negativeItems[5];
+ public static final Item minusSix = negativeItems[6];
+ public static final Item minusSeven = negativeItems[7];
+ public static final Item minusEight = negativeItems[8];
+ public static final Item minusNone = negativeItems[9];
+ public static final Item minusTen = negativeItems[10];
+
+ // elements expected to be missing
+ public static final Item fortytwo = new Item(42);
+ public static final Item eightysix = new Item(86);
+ public static final Item ninetynine = new Item(99);
+
+ // Interop across Item, int
+
+ static void mustEqual(Item x, Item y) {
+ if (x != y)
+ assertEquals(x.value, y.value);
+ }
+ static void mustEqual(Item x, int y) {
+ assertEquals(x.value, y);
+ }
+ static void mustEqual(int x, Item y) {
+ assertEquals(x, y.value);
+ }
+ static void mustEqual(int x, int y) {
+ assertEquals(x, y);
+ }
+ static void mustEqual(Object x, Object y) {
+ if (x != y)
+ assertEquals(x, y);
+ }
+ static void mustEqual(int x, Object y) {
+ if (y instanceof Item)
+ assertEquals(x, ((Item)y).value);
+ else fail();
+ }
+ static void mustEqual(Object x, int y) {
+ if (x instanceof Item)
+ assertEquals(((Item)x).value, y);
+ else fail();
+ }
+ static void mustEqual(boolean x, boolean y) {
+ assertEquals(x, y);
+ }
+ static void mustEqual(long x, long y) {
+ assertEquals(x, y);
+ }
+ static void mustEqual(double x, double y) {
+ assertEquals(x, y);
+ }
+ static void mustContain(Collection c, int i) {
+ assertTrue(c.contains(itemFor(i)));
+ }
+ static void mustContain(Collection c, Item i) {
+ assertTrue(c.contains(i));
+ }
+ static void mustNotContain(Collection c, int i) {
+ assertFalse(c.contains(itemFor(i)));
+ }
+ static void mustNotContain(Collection c, Item i) {
+ assertFalse(c.contains(i));
+ }
+ static void mustRemove(Collection c, int i) {
+ assertTrue(c.remove(itemFor(i)));
+ }
+ static void mustRemove(Collection c, Item i) {
+ assertTrue(c.remove(i));
+ }
+ static void mustNotRemove(Collection c, int i) {
+ Item[] items = defaultItems;
+ Item x = (i >= 0 && i < items.length) ? items[i] : new Item(i);
+ assertFalse(c.remove(x));
+ }
+ static void mustNotRemove(Collection c, Item i) {
+ assertFalse(c.remove(i));
+ }
+ static void mustAdd(Collection c, int i) {
+ assertTrue(c.add(itemFor(i)));
+ }
+ static void mustAdd(Collection c, Item i) {
+ assertTrue(c.add(i));
+ }
+ static void mustOffer(Queue c, int i) {
+ assertTrue(c.offer(itemFor(i)));
+ }
+ static void mustOffer(Queue c, Item i) {
+ assertTrue(c.offer(i));
+ }
/**
* Runs Runnable r with a security policy that permits precisely
@@ -1358,6 +1545,20 @@ public class JSR166TestCase extends Test
}
/**
+ * Spin-waits up to LONG_DELAY_MS milliseconds for the current thread to
+ * be interrupted. Clears the interrupt status before returning.
+ */
+ void awaitInterrupted() {
+ for (long startTime = 0L; !Thread.interrupted(); ) {
+ if (startTime == 0L)
+ startTime = System.nanoTime();
+ else if (millisElapsedSince(startTime) > LONG_DELAY_MS)
+ fail("timed out waiting for thread interrupt");
+ Thread.yield();
+ }
+ }
+
+ /**
* Returns the number of milliseconds since time given by
* startNanoTime, which must have been previously returned from a
* call to {@link System#nanoTime()}.
@@ -1366,19 +1567,6 @@ public class JSR166TestCase extends Test
return NANOSECONDS.toMillis(System.nanoTime() - startNanoTime);
}
-// void assertTerminatesPromptly(long timeoutMillis, Runnable r) {
-// long startTime = System.nanoTime();
-// try {
-// r.run();
-// } catch (Throwable fail) { threadUnexpectedException(fail); }
-// if (millisElapsedSince(startTime) > timeoutMillis/2)
-// throw new AssertionError("did not return promptly");
-// }
-
-// void assertTerminatesPromptly(Runnable r) {
-// assertTerminatesPromptly(LONG_DELAY_MS/2, r);
-// }
-
/**
* Checks that timed f.get() returns the expected value, and does not
* wait for the timeout to elapse before returning.
@@ -1409,19 +1597,33 @@ public class JSR166TestCase extends Test
}
/**
+ * Returns a new started daemon Thread running the given action,
+ * wrapped in a CheckedRunnable.
+ */
+ Thread newStartedThread(Action action) {
+ return newStartedThread(checkedRunnable(action));
+ }
+
+ /**
* Waits for the specified time (in 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, long timeoutMillis) {
+ void awaitTermination(Thread thread, long timeoutMillis) {
try {
- t.join(timeoutMillis);
+ thread.join(timeoutMillis);
} catch (InterruptedException fail) {
threadUnexpectedException(fail);
- } finally {
- if (t.getState() != Thread.State.TERMINATED) {
- t.interrupt();
- threadFail("timed out waiting for thread to terminate");
+ }
+ if (thread.getState() != Thread.State.TERMINATED) {
+ String detail = String.format(
+ "timed out waiting for thread to terminate, thread=%s, state=%s" ,
+ thread, thread.getState());
+ try {
+ threadFail(detail);
+ } finally {
+ // Interrupt thread __after__ having reported its stack trace
+ thread.interrupt();
}
}
}
@@ -1449,6 +1651,13 @@ public class JSR166TestCase extends Test
}
}
+ Runnable checkedRunnable(Action action) {
+ return new CheckedRunnable() {
+ public void realRun() throws Throwable {
+ action.run();
+ }};
+ }
+
public abstract class ThreadShouldThrow extends Thread {
protected abstract void realRun() throws Throwable;
@@ -1503,7 +1712,7 @@ public class JSR166TestCase extends Test
public void run() {}
}
- public static class NoOpCallable implements Callable {
+ public static class NoOpCallable implements Callable