mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2025-11-10 15:36:38 +01:00
Initial test cases for NostrClient and extensions
This commit is contained in:
@@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.sockets.okhttp.BasicOkHttpWebSocket
|
||||||
|
import com.vitorpamplona.quartz.utils.Log
|
||||||
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
open class BaseNostrClientTest {
|
||||||
|
companion object {
|
||||||
|
// Exists to avoid exceptions stopping the coroutine
|
||||||
|
val exceptionHandler =
|
||||||
|
CoroutineExceptionHandler { _, throwable ->
|
||||||
|
Log.e("AmethystCoroutine", "Caught exception: ${throwable.message}", throwable)
|
||||||
|
fail("Should not fail")
|
||||||
|
}
|
||||||
|
|
||||||
|
val appScope = CoroutineScope(Dispatchers.Default + SupervisorJob() + exceptionHandler)
|
||||||
|
val rootClient = OkHttpClient.Builder().build()
|
||||||
|
val socketBuilder = BasicOkHttpWebSocket.Builder { url -> rootClient }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.downloadFirstEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class NostrClientFirstEventTest : BaseNostrClientTest() {
|
||||||
|
@Test
|
||||||
|
fun testDownloadFirstEvent() =
|
||||||
|
runBlocking {
|
||||||
|
val client = NostrClient(socketBuilder, appScope)
|
||||||
|
|
||||||
|
val event =
|
||||||
|
client.downloadFirstEvent(
|
||||||
|
relay = "wss://nos.lol",
|
||||||
|
filter =
|
||||||
|
Filter(
|
||||||
|
kinds = listOf(MetadataEvent.KIND),
|
||||||
|
authors = listOf("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
assertEquals(MetadataEvent.KIND, event?.kind)
|
||||||
|
assertEquals("460c25e682fda7832b52d1f22d3d22b3176d972f60dcdc3212ed8c92ef85065c", event?.pubKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class NostrClientManualSubTest : BaseNostrClientTest() {
|
||||||
|
@Test
|
||||||
|
fun testEoseAfter100Events() =
|
||||||
|
runBlocking {
|
||||||
|
val client = NostrClient(socketBuilder, appScope)
|
||||||
|
|
||||||
|
val resultChannel = Channel<String>(UNLIMITED)
|
||||||
|
val events = mutableListOf<String>()
|
||||||
|
val mySubId = "test-sub-id-1"
|
||||||
|
|
||||||
|
val listener =
|
||||||
|
object : IRelayClientListener {
|
||||||
|
override fun onEvent(
|
||||||
|
relay: IRelayClient,
|
||||||
|
subId: String,
|
||||||
|
event: Event,
|
||||||
|
arrivalTime: Long,
|
||||||
|
afterEOSE: Boolean,
|
||||||
|
) {
|
||||||
|
if (mySubId == subId) {
|
||||||
|
resultChannel.trySend(event.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEOSE(
|
||||||
|
relay: IRelayClient,
|
||||||
|
subId: String,
|
||||||
|
arrivalTime: Long,
|
||||||
|
) {
|
||||||
|
if (mySubId == subId) {
|
||||||
|
resultChannel.trySend("EOSE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.subscribe(listener)
|
||||||
|
|
||||||
|
val filters =
|
||||||
|
mapOf(
|
||||||
|
RelayUrlNormalizer.normalize("wss://relay.damus.io") to
|
||||||
|
listOf(
|
||||||
|
Filter(
|
||||||
|
kinds = listOf(MetadataEvent.KIND),
|
||||||
|
limit = 100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.openReqSubscription(mySubId, filters)
|
||||||
|
|
||||||
|
withTimeoutOrNull(30000) {
|
||||||
|
while (events.size < 101) {
|
||||||
|
val event = resultChannel.receive()
|
||||||
|
events.add(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultChannel.close()
|
||||||
|
|
||||||
|
client.close(mySubId)
|
||||||
|
client.unsubscribe(listener)
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
assertEquals(101, events.size)
|
||||||
|
assertEquals(true, events.take(100).all { it.length == 64 })
|
||||||
|
assertEquals("EOSE", events[100])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.listeners.IRelayClientListener
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.single.IRelayClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip65RelayList.AdvertisedRelayListEvent
|
||||||
|
import com.vitorpamplona.quartz.utils.Log
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
||||||
|
import kotlinx.coroutines.coroutineScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class NostrClientRepeatSubTest : BaseNostrClientTest() {
|
||||||
|
@Test
|
||||||
|
fun testRepeatSubEvents() =
|
||||||
|
runBlocking {
|
||||||
|
val client = NostrClient(socketBuilder, appScope)
|
||||||
|
|
||||||
|
val resultChannel = Channel<String>(UNLIMITED)
|
||||||
|
val events = mutableListOf<String>()
|
||||||
|
val mySubId = "test-sub-id-2"
|
||||||
|
|
||||||
|
val listener =
|
||||||
|
object : IRelayClientListener {
|
||||||
|
override fun onEvent(
|
||||||
|
relay: IRelayClient,
|
||||||
|
subId: String,
|
||||||
|
event: Event,
|
||||||
|
arrivalTime: Long,
|
||||||
|
afterEOSE: Boolean,
|
||||||
|
) {
|
||||||
|
if (mySubId == subId) {
|
||||||
|
resultChannel.trySend(event.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEOSE(
|
||||||
|
relay: IRelayClient,
|
||||||
|
subId: String,
|
||||||
|
arrivalTime: Long,
|
||||||
|
) {
|
||||||
|
if (mySubId == subId) {
|
||||||
|
resultChannel.trySend("EOSE")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.subscribe(listener)
|
||||||
|
|
||||||
|
val filters =
|
||||||
|
mapOf(
|
||||||
|
RelayUrlNormalizer.normalize("wss://relay.damus.io") to
|
||||||
|
listOf(
|
||||||
|
Filter(
|
||||||
|
kinds = listOf(MetadataEvent.KIND),
|
||||||
|
limit = 100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
val filters2 =
|
||||||
|
mapOf(
|
||||||
|
RelayUrlNormalizer.normalize("wss://relay.damus.io") to
|
||||||
|
listOf(
|
||||||
|
Filter(
|
||||||
|
kinds = listOf(AdvertisedRelayListEvent.KIND),
|
||||||
|
limit = 100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
coroutineScope {
|
||||||
|
launch {
|
||||||
|
withTimeoutOrNull(30000) {
|
||||||
|
while (events.size < 202) {
|
||||||
|
// simulates an update in the middle of the sub
|
||||||
|
if (events.size == 1) {
|
||||||
|
client.openReqSubscription(mySubId, filters2)
|
||||||
|
}
|
||||||
|
val event = resultChannel.receive()
|
||||||
|
Log.d("OkHttpWebsocketListener", "Processing: ${events.size} $event")
|
||||||
|
events.add(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
launch {
|
||||||
|
client.openReqSubscription(mySubId, filters)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.close(mySubId)
|
||||||
|
client.unsubscribe(listener)
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
assertEquals(202, events.size)
|
||||||
|
assertEquals(true, events.take(100).all { it.length == 64 })
|
||||||
|
assertEquals("EOSE", events[100])
|
||||||
|
assertEquals(true, events.drop(101).take(100).all { it.length == 64 })
|
||||||
|
assertEquals("EOSE", events[201])
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.crypto.KeyPair
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.accessories.sendAndWaitForResponse
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.signers.NostrSignerInternal
|
||||||
|
import com.vitorpamplona.quartz.nip10Notes.TextNoteEvent
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class NostrClientSendAndWaitTest : BaseNostrClientTest() {
|
||||||
|
@Test
|
||||||
|
fun testSendAndWaitForResponse() =
|
||||||
|
runBlocking {
|
||||||
|
val client = NostrClient(socketBuilder, appScope)
|
||||||
|
|
||||||
|
val randomSigner = NostrSignerInternal(KeyPair())
|
||||||
|
|
||||||
|
val event = randomSigner.sign(TextNoteEvent.build("Hello World"))
|
||||||
|
|
||||||
|
val resultDamus =
|
||||||
|
client.sendAndWaitForResponse(
|
||||||
|
event = event,
|
||||||
|
relayList = setOf(RelayUrlNormalizer.normalize("wss://relay.damus.io")),
|
||||||
|
)
|
||||||
|
|
||||||
|
val resultNos =
|
||||||
|
client.sendAndWaitForResponse(
|
||||||
|
event = event,
|
||||||
|
relayList = setOf(RelayUrlNormalizer.normalize("wss://nos.lol")),
|
||||||
|
)
|
||||||
|
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
assertEquals(true, resultDamus)
|
||||||
|
assertEquals(false, resultNos)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2025 Vitor Pamplona
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||||
|
* this software and associated documentation files (the "Software"), to deal in
|
||||||
|
* the Software without restriction, including without limitation the rights to use,
|
||||||
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
|
||||||
|
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||||
|
* subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||||
|
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.vitorpamplona.quartz.nip01Core.relay
|
||||||
|
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.core.Event
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.metadata.MetadataEvent
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClient
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.client.NostrClientSubscription
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.filters.Filter
|
||||||
|
import com.vitorpamplona.quartz.nip01Core.relay.normalizer.RelayUrlNormalizer
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.channels.Channel.Factory.UNLIMITED
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.coroutines.withTimeoutOrNull
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class NostrClientSubscriptionTest : BaseNostrClientTest() {
|
||||||
|
@Test
|
||||||
|
fun testNostrClientSubscription() =
|
||||||
|
runBlocking {
|
||||||
|
val client = NostrClient(socketBuilder, appScope)
|
||||||
|
|
||||||
|
val resultChannel = Channel<Event>(UNLIMITED)
|
||||||
|
val events = mutableSetOf<Event>()
|
||||||
|
|
||||||
|
val sub =
|
||||||
|
NostrClientSubscription(
|
||||||
|
client = client,
|
||||||
|
filter = {
|
||||||
|
mapOf(
|
||||||
|
RelayUrlNormalizer.normalize("wss://relay.damus.io") to
|
||||||
|
listOf(
|
||||||
|
Filter(
|
||||||
|
kinds = listOf(MetadataEvent.KIND),
|
||||||
|
limit = 100,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { event ->
|
||||||
|
assertEquals(MetadataEvent.KIND, event.kind)
|
||||||
|
resultChannel.trySend(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
withTimeoutOrNull(30000) {
|
||||||
|
while (events.size < 100) {
|
||||||
|
val event = resultChannel.receive()
|
||||||
|
events.add(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resultChannel.close()
|
||||||
|
|
||||||
|
sub.closeSubscription()
|
||||||
|
|
||||||
|
client.disconnect()
|
||||||
|
|
||||||
|
assertEquals(100, events.size)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user