diff --git a/modules/core/src/appleTest/kotlin/fr/acinq/lightning/tests/utils/runTest.apple.kt b/modules/core/src/appleTest/kotlin/fr/acinq/lightning/tests/utils/runTest.apple.kt deleted file mode 100644 index f358a0f8d..000000000 --- a/modules/core/src/appleTest/kotlin/fr/acinq/lightning/tests/utils/runTest.apple.kt +++ /dev/null @@ -1,22 +0,0 @@ -package fr.acinq.lightning.tests.utils - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.launch -import platform.Foundation.NSDate -import platform.Foundation.NSRunLoop -import platform.Foundation.dateWithTimeIntervalSinceNow -import platform.Foundation.runUntilDate - -actual fun runSuspendBlocking(block: suspend CoroutineScope.() -> Unit) { - var result: Result? = null - - MainScope().launch { - result = kotlin.runCatching { block() } - } - - while (result == null) NSRunLoop.mainRunLoop.runUntilDate(NSDate.dateWithTimeIntervalSinceNow(0.01)) - - result.getOrThrow() - -} diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletIntegrationTest.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletIntegrationTest.kt index cf3dcd376..5360d8e26 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletIntegrationTest.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumMiniWalletIntegrationTest.kt @@ -1,29 +1,21 @@ package fr.acinq.lightning.blockchain.electrum -import fr.acinq.bitcoin.* +import fr.acinq.bitcoin.Chain +import fr.acinq.bitcoin.MnemonicCode import fr.acinq.bitcoin.utils.runTrying -import fr.acinq.lightning.SwapInParams -import fr.acinq.lightning.blockchain.fee.FeeratePerKw import fr.acinq.lightning.crypto.LocalKeyManager import fr.acinq.lightning.io.TcpSocket -import fr.acinq.lightning.io.TcpSocket.Builder.Companion.invoke import fr.acinq.lightning.tests.TestConstants import fr.acinq.lightning.tests.bitcoind.BitcoindService import fr.acinq.lightning.tests.utils.LightningTestSuite -import fr.acinq.lightning.tests.utils.readEnvironmentVariable -import fr.acinq.lightning.tests.utils.runSuspendBlocking import fr.acinq.lightning.tests.utils.runSuspendTest import fr.acinq.lightning.utils.ServerAddress -import fr.acinq.lightning.utils.sat import fr.acinq.lightning.utils.toByteVector -import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.* -import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.flow.first import kotlin.test.Test -import kotlin.test.assertContains import kotlin.test.assertEquals import kotlin.time.Duration.Companion.seconds @@ -35,12 +27,12 @@ class ElectrumMiniWalletIntegrationTest : LightningTestSuite() { private val keyManager = LocalKeyManager(MnemonicCode.toSeed(mnemonics, "").toByteVector(), Chain.Regtest, TestConstants.aliceSwapInServerXpub) init { - runSuspendBlocking { - withTimeout(10.seconds) { - while (runTrying { bitcoincli.getNetworkInfo() }.isFailure) { - delay(0.5.seconds) - } + runSuspendTest(timeout = 10.seconds) { + while (runTrying { bitcoincli.getNetworkInfo() }.isFailure) { + delay(0.5.seconds) } + } + runSuspendTest { val address = bitcoincli.getNewAddress() val address0 = keyManager.swapInOnChainWallet.getSwapInProtocol(0).address(Chain.Regtest) bitcoincli.sendToAddress(address0, 1.0) diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt index acf4be88b..ee7ab5569 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/blockchain/electrum/ElectrumWatcherIntegrationTest.kt @@ -2,7 +2,6 @@ package fr.acinq.lightning.blockchain.electrum import fr.acinq.bitcoin.* import fr.acinq.bitcoin.Bitcoin.addressToPublicKeyScript -import fr.acinq.bitcoin.SigHash.SIGHASH_ALL import fr.acinq.bitcoin.utils.runTrying import fr.acinq.lightning.blockchain.WatchConfirmed import fr.acinq.lightning.blockchain.WatchConfirmedTriggered @@ -11,14 +10,12 @@ import fr.acinq.lightning.blockchain.WatchSpentTriggered import fr.acinq.lightning.io.TcpSocket import fr.acinq.lightning.tests.bitcoind.BitcoindService import fr.acinq.lightning.tests.utils.LightningTestSuite -import fr.acinq.lightning.tests.utils.runSuspendBlocking import fr.acinq.lightning.tests.utils.runSuspendTest import fr.acinq.lightning.utils.ServerAddress import fr.acinq.lightning.utils.currentTimestampMillis import fr.acinq.lightning.utils.sat import kotlinx.coroutines.delay import kotlinx.coroutines.flow.first -import kotlinx.coroutines.withTimeout import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue @@ -30,11 +27,9 @@ class ElectrumWatcherIntegrationTest : LightningTestSuite() { private val bitcoincli = BitcoindService init { - runSuspendBlocking { - withTimeout(10.seconds) { - while (runTrying { bitcoincli.getNetworkInfo() }.isFailure) { - delay(0.5.seconds) - } + runSuspendTest(timeout = 10.seconds) { + while (runTrying { bitcoincli.getNetworkInfo() }.isFailure) { + delay(0.5.seconds) } } } diff --git a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/tests/utils/runTest.kt b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/tests/utils/runTest.kt index bf39cceb7..98976139a 100644 --- a/modules/core/src/commonTest/kotlin/fr/acinq/lightning/tests/utils/runTest.kt +++ b/modules/core/src/commonTest/kotlin/fr/acinq/lightning/tests/utils/runTest.kt @@ -1,26 +1,21 @@ package fr.acinq.lightning.tests.utils import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.cancel -import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeout +import kotlinx.coroutines.cancelChildren +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.withTimeoutOrNull +import kotlin.test.fail import kotlin.time.Duration import kotlin.time.Duration.Companion.seconds -/** - * This defers to kotlin's [kotlinx.coroutines.runBlocking] on all platforms except Apple targets, which need custom code: - * NativeSocket delivers its callbacks on the main GCD queue, so the test body runs on the main dispatcher while the test - * runner pumps the main run loop (a plain runBlocking would park the main thread and the callbacks would never fire). - */ -expect fun runSuspendBlocking(block: suspend CoroutineScope.() -> Unit) - -fun runSuspendTest(timeout: Duration = 30.seconds, test: suspend CoroutineScope.() -> Unit) { - runSuspendBlocking { - withTimeout(timeout) { - launch { - test() - cancel() - }.join() - } - } +fun runSuspendTest(timeout: Duration = 30.seconds, test: suspend CoroutineScope.() -> Unit) = runBlocking { + // withTimeoutOrNull only swallows its own timeout: an exception thrown by the test body — including a + // TimeoutCancellationException from a withTimeout inside the test — propagates and fails the test + withTimeoutOrNull(timeout) { + test() + // the test body has returned: cancel whatever it left running in its scope, otherwise this scope + // would never complete; withTimeoutOrNull only resumes once those coroutines have finished their + // cancellation cleanup, so nothing they print can be misattributed by gradle's test runner + coroutineContext.cancelChildren() + } ?: fail("test did not complete within $timeout") } diff --git a/modules/core/src/jvmTest/kotlin/fr/acinq/lightning/tests/util/runTestJvm.kt b/modules/core/src/jvmTest/kotlin/fr/acinq/lightning/tests/util/runTestJvm.kt deleted file mode 100644 index 97c05b463..000000000 --- a/modules/core/src/jvmTest/kotlin/fr/acinq/lightning/tests/util/runTestJvm.kt +++ /dev/null @@ -1,6 +0,0 @@ -package fr.acinq.lightning.tests.utils - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -actual fun runSuspendBlocking(block: suspend CoroutineScope.() -> Unit) = runBlocking { block() } diff --git a/modules/core/src/linuxTest/kotlin/fr/acinq/lightning/tests/utils/runTestLinux.kt b/modules/core/src/linuxTest/kotlin/fr/acinq/lightning/tests/utils/runTestLinux.kt deleted file mode 100644 index 5ebd5566c..000000000 --- a/modules/core/src/linuxTest/kotlin/fr/acinq/lightning/tests/utils/runTestLinux.kt +++ /dev/null @@ -1,6 +0,0 @@ -package fr.acinq.lightning.tests.utils - -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.runBlocking - -actual fun runSuspendBlocking(block: suspend CoroutineScope.() -> Unit) = runBlocking { block() } \ No newline at end of file