From f383bdb0bc4da5dd58827ee5405b122174f36485 Mon Sep 17 00:00:00 2001 From: Hongchol Sinn Date: Mon, 29 Jun 2026 15:15:29 -0700 Subject: [PATCH 1/2] fix: hanging test - Replace Object lock/wait/notify synchronization with CountDownLatch. ai-assisted=yes TNZ-115123 --- .../RetryingEncryptionServiceTest.java | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java b/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java index 4659fccb9..afdb7a4b6 100644 --- a/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java +++ b/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java @@ -2,6 +2,8 @@ import java.security.ProviderException; import java.util.UUID; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.crypto.IllegalBlockSizeException; @@ -221,7 +223,7 @@ public void encryption_encryptionLocks_acquiresALunaUsageReadLock() throws Excep @Test public void whenUsingTwoThreads_wontRetryTwice() throws Exception { - final Object lock = new Object(); + final CountDownLatch latch = new CountDownLatch(1); final Thread firstThread = new Thread("first") { @Override public void run() { @@ -243,7 +245,7 @@ public void run() { } }; - subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, lock); + subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); when(keySet.getActive()) .thenReturn(firstActiveKey); when(firstActiveKey.encrypt(anyString())) @@ -413,7 +415,7 @@ public void decryptionLocks_acquiresALunaUsageReadLock() throws Exception { @Test public void usingTwoThread_wontRetryTwice() throws Exception { - final Object lock = new Object(); + final CountDownLatch latch = new CountDownLatch(1); final Thread firstThread = new Thread("first") { @Override public void run() { @@ -435,7 +437,7 @@ public void run() { } }; - subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, lock); + subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); when(keySet.get(activeKeyUuid)) .thenReturn(firstActiveKey); @@ -462,13 +464,13 @@ private class RacingRetryingEncryptionServiceForTest extends RetryingEncryptionS private final Thread firstThread; private final Thread secondThread; - private final Object lock; + private final CountDownLatch latch; - RacingRetryingEncryptionServiceForTest(final Thread firstThread, final Thread secondThread, final Object lock) { + RacingRetryingEncryptionServiceForTest(final Thread firstThread, final Thread secondThread, final CountDownLatch latch) { super(RetryingEncryptionServiceTest.this.keySet); this.firstThread = firstThread; this.secondThread = secondThread; - this.lock = lock; + this.latch = latch; } @Override @@ -476,14 +478,10 @@ public void setNeedsReconnectFlag() { try { if (Thread.currentThread().equals(firstThread)) { secondThread.start(); - synchronized (lock) { - lock.wait(); // pause the first thread - } + latch.await(10, TimeUnit.SECONDS); // pause the first thread until secondThread signals Thread.sleep(10); // give thread two a chance to get all the way through the retry } else { - synchronized (lock) { - lock.notify(); // unpause the first thread - } + latch.countDown(); // unpause the first thread } } catch (final Exception e) { //do nothing From 29287ab80ff8bd915888756569df60a54da1e3ac Mon Sep 17 00:00:00 2001 From: Hongchol Sinn Date: Tue, 30 Jun 2026 11:57:51 -0700 Subject: [PATCH 2/2] fix: assert latch was signalled within timeout in two-thread tests ai-assisted=yes TNZ-115123 --- .../services/RetryingEncryptionServiceTest.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java b/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java index afdb7a4b6..84457d6cd 100644 --- a/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java +++ b/components/encryption/src/test/java/org/cloudfoundry/credhub/services/RetryingEncryptionServiceTest.java @@ -19,6 +19,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -245,7 +246,8 @@ public void run() { } }; - subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); + final RacingRetryingEncryptionServiceForTest racingSubject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); + subject = racingSubject; when(keySet.getActive()) .thenReturn(firstActiveKey); when(firstActiveKey.encrypt(anyString())) @@ -258,6 +260,7 @@ public void run() { firstThread.join(); secondThread.join(); + assertTrue(racingSubject.latchSignalled, "secondThread did not signal the latch within the timeout period"); verify(keySet, times(1)).reload(); } @@ -437,7 +440,8 @@ public void run() { } }; - subject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); + final RacingRetryingEncryptionServiceForTest racingSubject = new RacingRetryingEncryptionServiceForTest(firstThread, secondThread, latch); + subject = racingSubject; when(keySet.get(activeKeyUuid)) .thenReturn(firstActiveKey); @@ -457,6 +461,7 @@ public void run() { firstThread.join(); secondThread.join(); + assertTrue(racingSubject.latchSignalled, "secondThread did not signal the latch within the timeout period"); verify(keySet, times(1)).reload(); } @@ -465,6 +470,7 @@ private class RacingRetryingEncryptionServiceForTest extends RetryingEncryptionS private final Thread firstThread; private final Thread secondThread; private final CountDownLatch latch; + volatile boolean latchSignalled = true; RacingRetryingEncryptionServiceForTest(final Thread firstThread, final Thread secondThread, final CountDownLatch latch) { super(RetryingEncryptionServiceTest.this.keySet); @@ -478,7 +484,7 @@ public void setNeedsReconnectFlag() { try { if (Thread.currentThread().equals(firstThread)) { secondThread.start(); - latch.await(10, TimeUnit.SECONDS); // pause the first thread until secondThread signals + latchSignalled = latch.await(10, TimeUnit.SECONDS); // pause the first thread until secondThread signals Thread.sleep(10); // give thread two a chance to get all the way through the retry } else { latch.countDown(); // unpause the first thread