From 42badac158ac18c7bfb8f1660d48c4b51b494e68 Mon Sep 17 00:00:00 2001 From: Dmitry Khalanskiy Date: Fri, 15 Nov 2024 11:01:24 +0100 Subject: [PATCH] Fix a flaky test Follow-up for #4227 This time, the fix is less likely to work just by accident. With enough loop iterations if we close the pool after each iteration, the current `develop` fails in 10/10 runs, whereas after this fix, running the test for 20 runs didn't fail once. --- .../jvm/test/JobChildStressTest.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/test/JobChildStressTest.kt b/kotlinx-coroutines-core/jvm/test/JobChildStressTest.kt index 46b7ee790a..981ad32ba9 100644 --- a/kotlinx-coroutines-core/jvm/test/JobChildStressTest.kt +++ b/kotlinx-coroutines-core/jvm/test/JobChildStressTest.kt @@ -8,7 +8,7 @@ import kotlin.test.* /** * Testing the procedure of attaching a child to the parent job. */ -class JobChildStressTest : TestBase() { +class JobChildStressTest : TestBase(disableOutCheck = true) { private val N_ITERATIONS = 10_000 * stressTestMultiplier private val pool = newFixedThreadPoolContext(3, "JobChildStressTest") @@ -77,6 +77,7 @@ class JobChildStressTest : TestBase() { fun testChildAttachmentRacingWithLastChildCompletion() { // All exceptions should get aggregated here repeat(N_ITERATIONS) { + val canCloseThePool = CountDownLatch(1) runBlocking { val rogueJob = AtomicReference() /** not using [createCompletableDeferredForTesting] because we don't need extra children. */ @@ -89,14 +90,11 @@ class JobChildStressTest : TestBase() { launch(pool + deferred) { deferred.complete(Unit) // Transition deferred into "completing" state waiting for current child // **Asynchronously** submit task that launches a child so it races with completion - try { - pool.executor.execute { - rogueJob.set(launch(pool + deferred) { - throw TestException("isCancelled: ${coroutineContext.job.isCancelled}") - }) - } - } catch (_: RejectedExecutionException) { - // This is expected if the pool is closed + pool.executor.execute { + rogueJob.set(launch(pool + deferred) { + throw TestException("isCancelled: ${coroutineContext.job.isCancelled}") + }) + canCloseThePool.countDown() } } @@ -104,6 +102,8 @@ class JobChildStressTest : TestBase() { val rogue = rogueJob.get() if (rogue?.isActive == true) { throw TestException("Rogue job $rogue with parent " + rogue.parent + " and children list: " + rogue.parent?.children?.toList()) + } else { + canCloseThePool.await() } } }