From f845d277e2558e6cd8f2d5c76de6c21483d244f4 Mon Sep 17 00:00:00 2001 From: AE <98699388+A-EDev@users.noreply.github.com> Date: Sat, 7 Nov 2026 20:30:27 +0200 Subject: [PATCH] test(sync): make a LAN scanner after the mailbox fail when a code is served again --- .../github/aedev/flow/sync2/LanPairingTest.kt | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/app/src/test/java/io/github/aedev/flow/sync2/LanPairingTest.kt b/app/src/test/java/io/github/aedev/flow/sync2/LanPairingTest.kt index a5a211b26..a85ab411f 100644 --- a/app/src/test/java/io/github/aedev/flow/sync2/LanPairingTest.kt +++ b/app/src/test/java/io/github/aedev/flow/sync2/LanPairingTest.kt @@ -27,6 +27,7 @@ import io.github.aedev.flow.sync2.linking.join import io.github.aedev.flow.sync2.linking.listenOn import io.github.aedev.flow.sync2.linking.newOffer import io.github.aedev.flow.sync2.linking.readCode +import io.github.aedev.flow.sync2.store.Mailbox import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.async import kotlinx.coroutines.coroutineScope @@ -42,6 +43,7 @@ import org.junit.Assert.assertTrue import org.junit.Test import org.junit.runner.RunWith import org.robolectric.annotation.Config +import java.util.concurrent.ConcurrentHashMap /** Pairing over a loopback WebSocket (spec/protocol.md, Channel), on real time: sockets don't follow a test clock. */ @RunWith(AndroidJUnit4::class) @@ -107,6 +109,18 @@ class LanPairingTest { assertEquals(listOf(LanAddressRow(added, "127.0.0.1", 4002)), memberDb.lan().addresses()) } + /** The store's mailbox, handing each message out once, so a shower that started over could only serve someone else. */ + private class OnceMailbox( + private val store: MemoryStore, + ) : Mailbox by store { + private val handedOut = ConcurrentHashMap.newKeySet() + + override suspend fun getMessage( + slot: String, + name: String, + ): ByteArray? = store.getMessage(slot, name)?.takeIf { handedOut.add(name) } + } + private fun firstMessage( offer: Offer, seed: Byte, @@ -184,16 +198,16 @@ class LanPairingTest { val slot = SyncBytes.toHex(pairingSlot(offer.token)) withContext(Dispatchers.Default) { coroutineScope { - val added = async { runCatching { addDevice(session, g.store, offer, g.a, LINK) { true } } } + val added = async { runCatching { addDevice(session, OnceMailbox(g.store), offer, g.a, LINK) { true } } } val first = MailboxPipe(g.store, slot, shower = false) while (runCatching { first.send(firstMessage(offer, 8)) }.isFailure) delay(50) assertArrayEquals(offer.public, first.receive()) - val second = connected(offer, firstMessage(offer, 9)) - assertNull(second?.next()) + val second = checkNotNull(connected(offer, firstMessage(offer, 9))) + assertNull(second.next()) first.send(ByteArray(100)) - assertNull("the code is finished", second?.next()) + assertNull("the code is finished", second.next()) assertTrue(added.await().isFailure) - second?.close() + second.close() } } }