diff options
author | Tobias Thierer <tobiast@google.com> | 2017-02-19 15:01:51 +0000 |
---|---|---|
committer | Tobias Thierer <tobiast@google.com> | 2017-02-19 17:13:51 +0000 |
commit | cff661d65e3e6e2ac731ebbf938251656deb4be4 (patch) | |
tree | d7174a0609e9bf7124733e593555e5b96cf2427c /jsr166-tests/src/test/java/jsr166/JSR166TestCase.java | |
parent | b2af2e6d63267a4ab475fd288e6a93e3a183b59b (diff) |
Port JSR166 LinkedTransferQueueTest flakiness fix
This CL cherry-picks the following upstream (*) test changes ("upstream"
here is JSR166's CVS repository
cvs -d ':pserver:anonymous@gee.cs.oswego.edu/home/jsr166/jsr166'
This is in contrast to the code under test, whose upstream is OpenJDK).
=====
src/test/tck/LinkedTransferQueueTest.java
revision 1.70
date: 2017/02/18 16:37:49; author: jsr166; state: Exp; lines: +11 -5
waitForThreadToEnterWaitState should fail on timeout; tests should tolerate transient blocking Thread.State at any time (e.g. due to classloading)
src/test/tck/JSR166TestCase.java
revision 1.219
date: 2017/02/18 16:37:49; author: jsr166; state: Exp; lines: +43 -3
waitForThreadToEnterWaitState should fail on timeout; tests should tolerate transient blocking Thread.State at any time (e.g. due to classloading)
src/test/tck/PhaserTest.java
revision 1.45
date: 2017/02/18 15:05:55; author: jsr166; state: Exp; lines: +10 -10
use default timeout of LONG_DELAY_MS with
waitForThreadToEnterWaitState
======
The effect of this CL is to fix flakiness in LinkedTransferQueueTest's
testTransfer2() and testWaitingConsumer().
These test methods need to wait until a background thread was blocked
waiting on a LinkedTransferQueue; before this CL, they did so by
calling a helper method that waited for the background thread's state
to become WAITING, TIMED_WAITING, or BLOCKED. After this CL, they also
check that the LinkedTransferQueue is in the expected state before
they stop waiting.
The additional check is necessary because LinkedTransferQueue uses
LockSupport.park(), which on Android involves a synchronized lock
and therefore BLOCKED state. This caused the test methods to
prematurely stop waiting, which caused the test to fail.
The concrete failure could also have been prevented by waiting for
the thread to enter WAITING or TIMED_WAITING state rather than BLOCKED.
This was considered but not chosen by upstream since it would still
have made assumptions about those states not being entered elsewhere.
This CL also changes the waiting logic to fail() the test upon
timeout. PhaserTest was changed to use longer timeouts (10sec
rather than 250msec) to avoid flaky timeout failures.
Bug: 34814528
Test: LinkedTransferQueueTest
Test: PhaserTest
Test: Checked that testTransfer2() and testWaitingConsumer() are
non-flaky by running their body 10,000 times each in a loop.
Change-Id: I112ee1fba8aea6ca97ca0f99bba0fc9f00e5c0c2
Diffstat (limited to 'jsr166-tests/src/test/java/jsr166/JSR166TestCase.java')
-rw-r--r-- | jsr166-tests/src/test/java/jsr166/JSR166TestCase.java | 46 |
1 files changed, 43 insertions, 3 deletions
diff --git a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java index fc1632cb8b..ca2add3310 100644 --- a/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java +++ b/jsr166-tests/src/test/java/jsr166/JSR166TestCase.java @@ -1221,21 +1221,61 @@ public class JSR166TestCase extends TestCase { fail("Unexpected thread termination"); else if (millisElapsedSince(startTime) > timeoutMillis) { threadAssertTrue(thread.isAlive()); - return; + fail("timed out waiting for thread to enter wait state"); } Thread.yield(); } } /** - * Waits up to LONG_DELAY_MS for the given thread to enter a wait - * state: BLOCKED, WAITING, or TIMED_WAITING. + * Spin-waits up to the specified number of milliseconds for the given + * thread to enter a wait state: BLOCKED, WAITING, or TIMED_WAITING, + * and additionally satisfy the given condition. + */ + void waitForThreadToEnterWaitState( + Thread thread, long timeoutMillis, Callable<Boolean> waitingForGodot) { + long startTime = 0L; + for (;;) { + Thread.State s = thread.getState(); + if (s == Thread.State.BLOCKED || + s == Thread.State.WAITING || + s == Thread.State.TIMED_WAITING) { + try { + if (waitingForGodot.call()) + return; + } catch (Throwable fail) { threadUnexpectedException(fail); } + } + else if (s == Thread.State.TERMINATED) + fail("Unexpected thread termination"); + else if (startTime == 0L) + startTime = System.nanoTime(); + else if (millisElapsedSince(startTime) > timeoutMillis) { + threadAssertTrue(thread.isAlive()); + fail("timed out waiting for thread to enter wait state"); + } + Thread.yield(); + } + } + + /** + * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to + * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING. */ void waitForThreadToEnterWaitState(Thread thread) { waitForThreadToEnterWaitState(thread, LONG_DELAY_MS); } /** + * Spin-waits up to LONG_DELAY_MS milliseconds for the given thread to + * enter a wait state: BLOCKED, WAITING, or TIMED_WAITING, + * and additionally satisfy the given condition. + */ + void waitForThreadToEnterWaitState( + Thread thread, Callable<Boolean> waitingForGodot) { + waitForThreadToEnterWaitState(thread, LONG_DELAY_MS, waitingForGodot); + } + + /** * Returns the number of milliseconds since time given by * startNanoTime, which must have been previously returned from a * call to {@link System#nanoTime()}. |