--- jsr166/src/test/tck/JSR166TestCase.java 2015/09/04 18:16:28 1.136
+++ jsr166/src/test/tck/JSR166TestCase.java 2015/10/03 16:57:25 1.149
@@ -37,7 +37,10 @@ import java.util.concurrent.BlockingQueu
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.RecursiveAction;
import java.util.concurrent.RecursiveTask;
@@ -65,18 +68,18 @@ import junit.framework.TestSuite;
*
*
*
- * - All assertions in code running in generated threads must use
+ *
- All assertions in code running in generated threads must use
* the forms {@link #threadFail}, {@link #threadAssertTrue}, {@link
* #threadAssertEquals}, or {@link #threadAssertNull}, (not
* {@code fail}, {@code assertTrue}, etc.) It is OK (but not
* particularly recommended) for other code to use these forms too.
* Only the most typically used JUnit assertion methods are defined
- * this way, but enough to live with.
+ * this way, but enough to live with.
*
- * - If you override {@link #setUp} or {@link #tearDown}, make sure
+ *
- If you override {@link #setUp} or {@link #tearDown}, make sure
* to invoke {@code super.setUp} and {@code super.tearDown} within
* them. These methods are used to clear and check for thread
- * assertion failures.
+ * assertion failures.
*
* - All delays and timeouts must use one of the constants {@code
* SHORT_DELAY_MS}, {@code SMALL_DELAY_MS}, {@code MEDIUM_DELAY_MS},
@@ -87,44 +90,44 @@ import junit.framework.TestSuite;
* is always discriminable as larger than SHORT and smaller than
* MEDIUM. And so on. These constants are set to conservative values,
* but even so, if there is ever any doubt, they can all be increased
- * in one spot to rerun tests on slower platforms.
+ * in one spot to rerun tests on slower platforms.
*
- * - All threads generated must be joined inside each test case
+ *
- 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
- * using Executors.
+ * using Executors.
*
*
*
* Other notes
*
*
- * - Usually, there is one testcase method per JSR166 method
+ *
- Usually, there is one testcase method per JSR166 method
* covering "normal" operation, and then as many exception-testing
* methods as there are exceptions the method can throw. Sometimes
* there are multiple tests per JSR166 method when the different
* "normal" behaviors differ significantly. And sometimes testcases
* cover multiple methods when they cannot be tested in
- * isolation.
+ * isolation.
*
- * - The documentation style for testcases is to provide as javadoc
+ *
- The documentation style for testcases is to provide as javadoc
* a simple sentence or two describing the property that the testcase
* method purports to test. The javadocs do not say anything about how
- * the property is tested. To find out, read the code.
+ * the property is tested. To find out, read the code.
*
- * - These tests are "conformance tests", and do not attempt to
+ *
- These tests are "conformance tests", and do not attempt to
* test throughput, latency, scalability or other performance factors
* (see the separate "jtreg" tests for a set intended to check these
* for the most central aspects of functionality.) So, most tests use
* the smallest sensible numbers of threads, collection sizes, etc
- * needed to check basic conformance.
+ * needed to check basic conformance.
*
* - The test classes currently do not declare inclusion in
* any particular package to simplify things for people integrating
- * them in TCK test suites.
+ * them in TCK test suites.
*
- * - As a convenience, the {@code main} of this class (JSR166TestCase)
- * runs all JSR166 unit tests.
+ * - As a convenience, the {@code main} of this class (JSR166TestCase)
+ * runs all JSR166 unit tests.
*
*
*/
@@ -183,27 +186,31 @@ public class JSR166TestCase extends Test
return (regex == null) ? null : Pattern.compile(regex);
}
- protected void runTest() throws Throwable {
+ public void runBare() throws Throwable {
if (methodFilter == null
- || methodFilter.matcher(toString()).find()) {
- for (int i = 0; i < runsPerTest; i++) {
- if (profileTests)
- runTestProfiled();
- else
- super.runTest();
- }
+ || methodFilter.matcher(toString()).find())
+ super.runBare();
+ }
+
+ protected void runTest() throws Throwable {
+ for (int i = 0; i < runsPerTest; i++) {
+ if (profileTests)
+ runTestProfiled();
+ else
+ super.runTest();
}
}
protected void runTestProfiled() throws Throwable {
- // Warmup run, notably to trigger all needed classloading.
- super.runTest();
- long t0 = System.nanoTime();
- try {
+ for (int i = 0; i < 2; i++) {
+ long startTime = System.nanoTime();
super.runTest();
- } finally {
- long elapsedMillis = millisElapsedSince(t0);
- if (elapsedMillis >= profileThreshold)
+ long elapsedMillis = millisElapsedSince(startTime);
+ if (elapsedMillis < profileThreshold)
+ break;
+ // 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);
}
}
@@ -282,12 +289,13 @@ public class JSR166TestCase extends Test
public static boolean atLeastJava7() { return JAVA_CLASS_VERSION >= 51.0; }
public static boolean atLeastJava8() { return JAVA_CLASS_VERSION >= 52.0; }
public static boolean atLeastJava9() {
- // As of 2015-09, java9 still uses 52.0 class file version
- return JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?(9|[0-9][0-9])$");
+ return JAVA_CLASS_VERSION >= 53.0
+ // As of 2015-09, java9 still uses 52.0 class file version
+ || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?(9|[0-9][0-9])$");
}
- // public static boolean atLeastJava9() { return JAVA_CLASS_VERSION >= 53.0; }
public static boolean atLeastJava10() {
- return JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?[0-9][0-9]$");
+ return JAVA_CLASS_VERSION >= 54.0
+ || JAVA_SPECIFICATION_VERSION.matches("^(1\\.)?[0-9][0-9]$");
}
/**
@@ -376,6 +384,7 @@ public class JSR166TestCase extends Test
"LongAdderTest",
"SplittableRandomTest",
"StampedLockTest",
+ "SubmissionPublisherTest",
"ThreadLocalRandom8Test",
};
addNamedTestClasses(suite, java8TestClassNames);
@@ -384,7 +393,7 @@ public class JSR166TestCase extends Test
// Java9+ test classes
if (atLeastJava9()) {
String[] java9TestClassNames = {
- "ThreadPoolExecutor9Test",
+ // Currently empty, but expecting varhandle tests
};
addNamedTestClasses(suite, java9TestClassNames);
}
@@ -516,6 +525,13 @@ public class JSR166TestCase extends Test
setDelays();
}
+ void tearDownFail(String format, Object... args) {
+ String msg = toString() + ": " + String.format(format, args);
+ System.err.println(msg);
+ printAllStackTraces();
+ throw new AssertionFailedError(msg);
+ }
+
/**
* Extra checks that get done for all test cases.
*
@@ -543,7 +559,7 @@ public class JSR166TestCase extends Test
}
if (Thread.interrupted())
- throw new AssertionFailedError("interrupt status set in main thread");
+ tearDownFail("interrupt status set in main thread");
checkForkJoinPoolThreadLeaks();
}
@@ -552,7 +568,7 @@ public class JSR166TestCase extends Test
* Finds missing try { ... } finally { joinPool(e); }
*/
void checkForkJoinPoolThreadLeaks() throws InterruptedException {
- Thread[] survivors = new Thread[5];
+ Thread[] survivors = new Thread[7];
int count = Thread.enumerate(survivors);
for (int i = 0; i < count; i++) {
Thread thread = survivors[i];
@@ -560,12 +576,15 @@ public class JSR166TestCase extends Test
if (name.startsWith("ForkJoinPool-")) {
// give thread some time to terminate
thread.join(LONG_DELAY_MS);
- if (!thread.isAlive()) continue;
- throw new AssertionFailedError
- (String.format("Found leaked ForkJoinPool thread test=%s thread=%s%n",
- toString(), name));
+ if (thread.isAlive())
+ tearDownFail("Found leaked ForkJoinPool thread thread=%s",
+ thread);
}
}
+
+ if (!ForkJoinPool.commonPool()
+ .awaitQuiescence(LONG_DELAY_MS, MILLISECONDS))
+ tearDownFail("ForkJoin common pool thread stuck");
}
/**
@@ -724,13 +743,23 @@ public class JSR166TestCase extends Test
}
/**
+ * Allows use of try-with-resources with per-test thread pools.
+ */
+ static class PoolCloser
+ implements AutoCloseable {
+ public final T pool;
+ public PoolCloser(T pool) { this.pool = pool; }
+ public void close() { joinPool(pool); }
+ }
+
+ /**
* Waits out termination of a thread pool or fails doing so.
*/
- void joinPool(ExecutorService exec) {
+ static void joinPool(ExecutorService pool) {
try {
- exec.shutdown();
- if (!exec.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS))
- fail("ExecutorService " + exec +
+ pool.shutdown();
+ if (!pool.awaitTermination(2 * LONG_DELAY_MS, MILLISECONDS))
+ fail("ExecutorService " + pool +
" did not terminate in a timely manner");
} catch (SecurityException ok) {
// Allowed in case test doesn't have privs
@@ -739,6 +768,34 @@ public class JSR166TestCase extends Test
}
}
+ /** Like Runnable, but with the freedom to throw anything */
+ interface Action { public void run() throws Throwable; }
+
+ /**
+ * Runs all the given actions in parallel, failing if any fail.
+ * Useful for running multiple variants of tests that are
+ * necessarily individually slow because they must block.
+ */
+ void testInParallel(Action ... actions) {
+ ExecutorService pool = Executors.newCachedThreadPool();
+ try {
+ ArrayList> futures = new ArrayList<>(actions.length);
+ for (final Action action : actions)
+ futures.add(pool.submit(new CheckedRunnable() {
+ public void realRun() throws Throwable { action.run();}}));
+ for (Future> future : futures)
+ try {
+ assertNull(future.get(LONG_DELAY_MS, MILLISECONDS));
+ } catch (ExecutionException ex) {
+ threadUnexpectedException(ex.getCause());
+ } catch (Exception ex) {
+ threadUnexpectedException(ex);
+ }
+ } finally {
+ joinPool(pool);
+ }
+ }
+
/**
* A debugging tool to print all stack traces, as jstack does.
*/
@@ -1191,7 +1248,10 @@ public class JSR166TestCase extends Test
public static final String TEST_STRING = "a test string";
public static class StringTask implements Callable {
- public String call() { return TEST_STRING; }
+ final String value;
+ public StringTask() { this(TEST_STRING); }
+ public StringTask(String value) { this.value = value; }
+ public String call() { return value; }
}
public Callable latchAwaitingStringTask(final CountDownLatch latch) {
@@ -1204,6 +1264,13 @@ public class JSR166TestCase extends Test
}};
}
+ public Runnable countDowner(final CountDownLatch latch) {
+ return new CheckedRunnable() {
+ public void realRun() throws InterruptedException {
+ latch.countDown();
+ }};
+ }
+
public Runnable awaiter(final CountDownLatch latch) {
return new CheckedRunnable() {
public void realRun() throws InterruptedException {