mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-07-30 19:46:17 +00:00
fix(geode): make multi-relay compliance test thread-safe
multiRelayPoolReturnsContentFromEachRelay flaked with "expected:<from-b> but was:<null>": the SubscriptionListener wrote the per-relay results into a plain HashMap/HashSet, but each relay delivers its EVENT/EOSE on its own InProcessWebSocket scope (Dispatchers.Default) and PoolRequests dispatches the listener callbacks outside any lock. Two relays therefore call `received[relay] = ...` concurrently, and a HashMap.put racing a rehash can drop an entry, leaving a relay's value null and failing the assertion. Use ConcurrentHashMap and ConcurrentHashMap.newKeySet() for the shared collections. Reproduced within 7 runs before the fix; 80 stress runs clean after. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HeAjLDNBvGPjb5bfViU3ad
This commit is contained in:
@@ -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<NormalizedRelayUrl, String>()
|
||||
val eosed = mutableSetOf<NormalizedRelayUrl>()
|
||||
// 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<NormalizedRelayUrl, String>()
|
||||
val eosed = ConcurrentHashMap.newKeySet<NormalizedRelayUrl>()
|
||||
val ch = Channel<Unit>(UNLIMITED)
|
||||
client.subscribe(
|
||||
"multi-1",
|
||||
|
||||
Reference in New Issue
Block a user