diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthEndpointsInteropTest.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthEndpointsInteropTest.kt index b6ef7f2ae..6e7e9046e 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthEndpointsInteropTest.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthEndpointsInteropTest.kt @@ -103,14 +103,13 @@ class NostrNestsAuthEndpointsInteropTest { @JvmStatic fun setUpHarness() { if (NostrNestsHarness.isEnabled()) { - harnessOrNull = NostrNestsHarness.start() + harnessOrNull = NostrNestsHarness.shared() } } @AfterClass @JvmStatic fun tearDownHarness() { - harnessOrNull?.close() harnessOrNull = null } } diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthFailureInteropTest.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthFailureInteropTest.kt index 64942a509..9a82180b7 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthFailureInteropTest.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthFailureInteropTest.kt @@ -217,14 +217,13 @@ class NostrNestsAuthFailureInteropTest { @JvmStatic fun setUpHarness() { if (NostrNestsHarness.isEnabled()) { - harnessOrNull = NostrNestsHarness.start() + harnessOrNull = NostrNestsHarness.shared() } } @AfterClass @JvmStatic fun tearDownHarness() { - harnessOrNull?.close() harnessOrNull = null } } diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthInteropTest.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthInteropTest.kt index b72f6a065..9eb5390e1 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthInteropTest.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsAuthInteropTest.kt @@ -72,14 +72,13 @@ class NostrNestsAuthInteropTest { @JvmStatic fun setUpHarness() { if (NostrNestsHarness.isEnabled()) { - harnessOrNull = NostrNestsHarness.start() + harnessOrNull = NostrNestsHarness.shared() } } @AfterClass @JvmStatic fun tearDownHarness() { - harnessOrNull?.close() harnessOrNull = null } } diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsHarness.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsHarness.kt index 7b9de6943..0d6f8efe9 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsHarness.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsHarness.kt @@ -89,11 +89,50 @@ class NostrNestsHarness private constructor( private const val PORT_READY_TIMEOUT_MS = 90_000L private const val PORT_PROBE_INTERVAL_MS = 500L + /** + * Process-level singleton instance. Once a test class brings the + * stack up, every other test class in the same JVM run shares + * the same containers — bringing the moq-relay Cargo build down + * and back up between every `@BeforeClass` is both slow (~30 s + * compile) and flaky (port-bind / network-create races leave + * the second start in a half-broken state). Container teardown + * is registered once with the JVM as a shutdown hook. + */ + @Volatile private var sharedInstance: NostrNestsHarness? = null + private val sharedLock = Any() + + /** + * Bring the stack up if not already running, returning the + * shared instance for this JVM run. Subsequent callers reuse + * the same containers. Use this in @BeforeClass. + */ + fun shared(): NostrNestsHarness { + sharedInstance?.let { return it } + synchronized(sharedLock) { + sharedInstance?.let { return it } + val instance = doStart() + Runtime + .getRuntime() + .addShutdownHook( + Thread({ + runCatching { instance.close() } + }, "NostrNestsHarness-shutdown"), + ) + sharedInstance = instance + return instance + } + } + /** * Bring the stack up. Caller must `close()` to tear it down — use * `try-with-resources` / Kotlin's `use { … }`. + * + * Most callers should use [shared] instead so the stack is + * reused across test classes. */ - fun start(): NostrNestsHarness { + fun start(): NostrNestsHarness = doStart() + + private fun doStart(): NostrNestsHarness { check(isEnabled()) { "NostrNestsHarness.start called without -D$ENABLE_PROPERTY=true. " + "Call NostrNestsHarness.assumeNestsInterop() first to skip cleanly." diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsMultiPeerInteropTest.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsMultiPeerInteropTest.kt index 72627e5a3..ab33a4779 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsMultiPeerInteropTest.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsMultiPeerInteropTest.kt @@ -392,14 +392,13 @@ class NostrNestsMultiPeerInteropTest { @JvmStatic fun setUpHarness() { if (NostrNestsHarness.isEnabled()) { - harnessOrNull = NostrNestsHarness.start() + harnessOrNull = NostrNestsHarness.shared() } } @AfterClass @JvmStatic fun tearDownHarness() { - harnessOrNull?.close() harnessOrNull = null } } diff --git a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsRoundTripInteropTest.kt b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsRoundTripInteropTest.kt index 3bf21fd3d..5d5e31723 100644 --- a/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsRoundTripInteropTest.kt +++ b/nestsClient/src/jvmTest/kotlin/com/vitorpamplona/nestsclient/interop/NostrNestsRoundTripInteropTest.kt @@ -268,14 +268,13 @@ class NostrNestsRoundTripInteropTest { @JvmStatic fun setUpHarness() { if (NostrNestsHarness.isEnabled()) { - harnessOrNull = NostrNestsHarness.start() + harnessOrNull = NostrNestsHarness.shared() } } @AfterClass @JvmStatic fun tearDownHarness() { - harnessOrNull?.close() harnessOrNull = null } }