fix(audio-rooms): share Docker harness across all interop test classes
Each interop test class was running its own NostrNestsHarness.start() in @BeforeClass and harnessOrNull?.close() in @AfterClass — meaning the Docker stack tore down + spun back up between every class. That sequence was both slow (~30 s Cargo build for moq-relay each time) and unreliable: leftover network state from the prior `down -v` was racing the next `up -d`, leaving moq-auth either unreachable (SocketException) or producing truncated 401 responses (EOFException on body.string()) for tests that ran after the first. Symptoms before this fix (first class wins; everything else fails): - NostrNestsAuthEndpointsInteropTest ✅ - NostrNestsAuthInteropTest → SocketException ❌ - NostrNestsAuthFailureInteropTest → EOFException ❌ - NostrNestsRoundTripInteropTest → "Failed to reach" ❌ - NostrNestsMultiPeerInteropTest → "Failed to reach" ❌ Fix: NostrNestsHarness.shared() returns a process-singleton. First caller does the docker compose up + port-probe; every subsequent caller reuses the same containers. Teardown is registered once via Runtime.addShutdownHook so the stack lives for the JVM's lifetime and dies cleanly at test process exit. All five test classes now call shared() in @BeforeClass; the @AfterClass blocks no longer call close() on the singleton (clearing the local reference is enough — the shutdown hook handles the real teardown). The original start() entry point is preserved for callers that want a per-call harness.
This commit is contained in:
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+40
-1
@@ -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."
|
||||
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user