diff --git a/geode/src/test/kotlin/com/vitorpamplona/geode/Nip01ComplianceTest.kt b/geode/src/test/kotlin/com/vitorpamplona/geode/Nip01ComplianceTest.kt index 41fc1b218e..4851956a13 100644 --- a/geode/src/test/kotlin/com/vitorpamplona/geode/Nip01ComplianceTest.kt +++ b/geode/src/test/kotlin/com/vitorpamplona/geode/Nip01ComplianceTest.kt @@ -39,6 +39,7 @@ import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeoutOrNull +import java.util.concurrent.ConcurrentHashMap import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertNull @@ -518,8 +519,13 @@ class Nip01ComplianceTest : RelayClientTest() { hub.getOrCreate(relayA).preload(fakeEvent(1, kind = 1, content = "from-a")) hub.getOrCreate(relayB).preload(fakeEvent(2, kind = 1, content = "from-b")) - val received = mutableMapOf() - val eosed = mutableSetOf() + // Each relay delivers its EVENT/EOSE on its own InProcessWebSocket + // scope, so these callbacks fire concurrently from two threads. The + // shared collections MUST be thread-safe — a plain HashMap loses a + // write when both threads put during a rehash, leaving a relay's + // entry null and flaking the assertions below. + val received = ConcurrentHashMap() + val eosed = ConcurrentHashMap.newKeySet() val ch = Channel(UNLIMITED) client.subscribe( "multi-1",