From 7b12370c0cd6b5c25ecb8dee8c00dcadd54fcaf5 Mon Sep 17 00:00:00 2001 From: Elliotte Rusty Harold Date: Tue, 4 Aug 2026 19:06:11 +0000 Subject: [PATCH] Fix deadlock in adapter access tests (all named-lock modules) NamedLockFactoryAdapterTestSupport has the same deadlock-prone winner/loser handshake as NamedLockFactoryTestSupport: when both competing threads fail to acquire the lock within the adapter lock wait time, both count down the loser latch and then block forever on winner.await(), so the winners latch is never released and the test hangs until @Timeout fires. Fix the copies in the ipc, hazelcast, redisson and maven-resolver-impl modules: - raise ADAPTER_TIME from 100 ms (500 ms in impl) to 1 s so at least one thread reliably wins even on a loaded machine; the loser is still queued behind the winner, so mutual exclusion is still verified - bound the winner/loser handshake and the test-side joins and latch awaits, and assert the expected outcome, so a pathological both-lose case fails fast with a clear message instead of hanging - bump the @Timeout(5) safety nets to @Timeout(15) to leave room for the longer loser path (2 attempts x ADAPTER_TIME + retry wait) This complements #2032 for the adapter-level tests. --- .../NamedLockFactoryAdapterTestSupport.java | 88 +++++++++---------- .../NamedLockFactoryAdapterTestSupport.java | 68 +++++++------- .../NamedLockFactoryAdapterTestSupport.java | 54 ++++++------ .../NamedLockFactoryAdapterTestSupport.java | 69 ++++++++------- 4 files changed, 140 insertions(+), 139 deletions(-) diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java index 57b63ac7b6..c5cedc738b 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/synccontext/NamedLockFactoryAdapterTestSupport.java @@ -50,7 +50,7 @@ * UT support for {@link SyncContextFactory}. */ public abstract class NamedLockFactoryAdapterTestSupport { - private static final long ADAPTER_TIME = 500L; + private static final long ADAPTER_TIME = 1000L; private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS; @@ -119,7 +119,7 @@ void multipleAcquires() { } @Test - @Timeout(5) + @Timeout(15) void multipleAcquiresWithALoser() throws InterruptedException { try (SyncContext syncContext1 = adapter.newInstance(session, false)) { syncContext1.acquire(Arrays.asList(new DefaultArtifact("groupId:artifactId:1.0")), null); @@ -133,13 +133,13 @@ void multipleAcquiresWithALoser() throws InterruptedException { } }); t1.start(); - t1.join(); - loser.await(); + t1.join(5000); + assertTrue(loser.await(5, TimeUnit.SECONDS), "expected a loser"); } } @Test - @Timeout(5) + @Timeout(15) public void sharedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers @@ -147,14 +147,14 @@ public void sharedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void exclusiveAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -162,14 +162,14 @@ public void exclusiveAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void mixedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -177,62 +177,62 @@ public void mixedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner (outer) CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner) Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test @@ -244,10 +244,10 @@ void fullyConsumeLockTime() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); long end = System.nanoTime(); long duration = end - start; long expectedDuration = ADAPTER_TIME_UNIT.toNanos(ADAPTER_TIME); @@ -261,9 +261,9 @@ void releasedExclusiveAllowAccess() throws InterruptedException { Thread t1 = new Thread(new Access(false, winners, losers, adapter, session, null)); new Access(false, winners, losers, adapter, session, null).run(); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } private static class Access implements Runnable { @@ -302,10 +302,10 @@ public void run() { if (chained != null) { chained.run(); } - loser.await(); + loser.await(5, TimeUnit.SECONDS); } catch (IllegalStateException | LockUpgradeNotSupportedException e) { loser.countDown(); - winner.await(); + winner.await(5, TimeUnit.SECONDS); } } catch (InterruptedException e) { fail("interrupted"); diff --git a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java index 6192a8e713..56adde92ba 100644 --- a/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-named-locks-hazelcast/src/test/java/org/eclipse/aether/named/hazelcast/NamedLockFactoryAdapterTestSupport.java @@ -50,7 +50,7 @@ public abstract class NamedLockFactoryAdapterTestSupport { protected static final HazelcastClientUtils utils = new HazelcastClientUtils(); - private static final long ADAPTER_TIME = 100L; + private static final long ADAPTER_TIME = 1000L; private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS; @@ -106,7 +106,7 @@ void justAcquire() { } @Test - @Timeout(5) + @Timeout(15) public void sharedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers @@ -114,14 +114,14 @@ public void sharedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void exclusiveAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -129,14 +129,14 @@ public void exclusiveAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void mixedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -144,62 +144,62 @@ public void mixedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner (outer) CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner) Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } private static class Access implements Runnable { @@ -238,10 +238,10 @@ public void run() { if (chained != null) { chained.run(); } - loser.await(); + loser.await(5, TimeUnit.SECONDS); } catch (IllegalStateException | LockUpgradeNotSupportedException e) { loser.countDown(); - winner.await(); + winner.await(5, TimeUnit.SECONDS); } } catch (InterruptedException e) { fail("interrupted"); diff --git a/maven-resolver-named-locks-ipc/src/test/java/org/eclipse/aether/named/ipc/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-named-locks-ipc/src/test/java/org/eclipse/aether/named/ipc/NamedLockFactoryAdapterTestSupport.java index 6ec259215f..aedb1e4dfd 100644 --- a/maven-resolver-named-locks-ipc/src/test/java/org/eclipse/aether/named/ipc/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-named-locks-ipc/src/test/java/org/eclipse/aether/named/ipc/NamedLockFactoryAdapterTestSupport.java @@ -48,7 +48,7 @@ */ @DisabledOnOs(value = OS.WINDOWS, disabledReason = "IPC named locks are not supported on Windows (Unix domain sockets)") public abstract class NamedLockFactoryAdapterTestSupport { - private static final long ADAPTER_TIME = 100L; + private static final long ADAPTER_TIME = 1000L; private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS; @@ -110,10 +110,10 @@ public void sharedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test @@ -125,10 +125,10 @@ public void exclusiveAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test @@ -140,10 +140,10 @@ public void mixedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test @@ -154,9 +154,9 @@ public void nestedSharedShared() throws InterruptedException { Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test @@ -167,9 +167,9 @@ public void nestedExclusiveShared() throws InterruptedException { Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test @@ -180,9 +180,9 @@ public void nestedExclusiveExclusive() throws InterruptedException { Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test @@ -193,9 +193,9 @@ public void nestedSharedExclusive() throws InterruptedException { Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } private static class Access implements Runnable { @@ -234,10 +234,10 @@ public void run() { if (chained != null) { chained.run(); } - loser.await(); + loser.await(5, TimeUnit.SECONDS); } catch (IllegalStateException | LockUpgradeNotSupportedException e) { loser.countDown(); - winner.await(); + winner.await(5, TimeUnit.SECONDS); } } catch (InterruptedException e) { fail("interrupted"); diff --git a/maven-resolver-named-locks-redisson/src/test/java/org/eclipse/aether/named/redisson/NamedLockFactoryAdapterTestSupport.java b/maven-resolver-named-locks-redisson/src/test/java/org/eclipse/aether/named/redisson/NamedLockFactoryAdapterTestSupport.java index 600bd5248d..22983b3000 100644 --- a/maven-resolver-named-locks-redisson/src/test/java/org/eclipse/aether/named/redisson/NamedLockFactoryAdapterTestSupport.java +++ b/maven-resolver-named-locks-redisson/src/test/java/org/eclipse/aether/named/redisson/NamedLockFactoryAdapterTestSupport.java @@ -42,6 +42,7 @@ import org.junit.jupiter.api.Timeout; import org.testcontainers.junit.jupiter.Testcontainers; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -54,7 +55,7 @@ public abstract class NamedLockFactoryAdapterTestSupport { protected static RedisContainer container = new RedisContainer(RedisContainer.DEFAULT_IMAGE_NAME.withTag(RedisContainer.DEFAULT_TAG)); - private static final long ADAPTER_TIME = 100L; + private static final long ADAPTER_TIME = 1000L; private static final TimeUnit ADAPTER_TIME_UNIT = TimeUnit.MILLISECONDS; @@ -108,7 +109,7 @@ void justAcquire() { } @Test - @Timeout(5) + @Timeout(15) public void sharedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers @@ -116,14 +117,14 @@ public void sharedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(true, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void exclusiveAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -131,14 +132,14 @@ public void exclusiveAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void mixedAccess() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser @@ -146,62 +147,62 @@ public void mixedAccess() throws InterruptedException { Thread t2 = new Thread(new Access(false, winners, losers, adapter, session, null)); t1.start(); t2.start(); - t1.join(); - t2.join(); - winners.await(); - losers.await(); + t1.join(5000); + t2.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveShared() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(true, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedExclusiveExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(2); // we expect 2 winners CountDownLatch losers = new CountDownLatch(0); // we expect 0 losers Thread t1 = new Thread(new Access( false, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected both threads to win"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected no loser"); } @Test - @Timeout(5) + @Timeout(15) public void nestedSharedExclusive() throws InterruptedException { CountDownLatch winners = new CountDownLatch(1); // we expect 1 winner (outer) CountDownLatch losers = new CountDownLatch(1); // we expect 1 loser (inner) Thread t1 = new Thread(new Access( true, winners, losers, adapter, session, new Access(false, winners, losers, adapter, session, null))); t1.start(); - t1.join(); - winners.await(); - losers.await(); + t1.join(5000); + assertTrue(winners.await(5, TimeUnit.SECONDS), "expected a winner"); + assertTrue(losers.await(5, TimeUnit.SECONDS), "expected a loser"); } private static class Access implements Runnable { @@ -240,10 +241,10 @@ public void run() { if (chained != null) { chained.run(); } - loser.await(); + loser.await(5, TimeUnit.SECONDS); } catch (IllegalStateException | LockUpgradeNotSupportedException e) { loser.countDown(); - winner.await(); + winner.await(5, TimeUnit.SECONDS); } } catch (InterruptedException e) { fail("interrupted");