From 7d40d29328ec6dabef9cfe384ac97cc7949e2c49 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Wed, 12 Mar 2025 13:36:09 +0100 Subject: [PATCH 1/5] Move krpc-ktor-server to commonMain --- krpc/krpc-ktor/krpc-ktor-server/build.gradle.kts | 4 ++-- krpc/krpc-ktor/krpc-ktor-server/gradle.properties | 6 ------ .../kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt | 2 +- .../kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt | 2 +- .../kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt | 2 +- .../kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt | 2 +- 6 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 krpc/krpc-ktor/krpc-ktor-server/gradle.properties rename krpc/krpc-ktor/krpc-ktor-server/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt (93%) rename krpc/krpc-ktor/krpc-ktor-server/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt (97%) rename krpc/krpc-ktor/krpc-ktor-server/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt (86%) rename krpc/krpc-ktor/krpc-ktor-server/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt (96%) diff --git a/krpc/krpc-ktor/krpc-ktor-server/build.gradle.kts b/krpc/krpc-ktor/krpc-ktor-server/build.gradle.kts index 042078e46..eb1011754 100644 --- a/krpc/krpc-ktor/krpc-ktor-server/build.gradle.kts +++ b/krpc/krpc-ktor/krpc-ktor-server/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ plugins { @@ -9,7 +9,7 @@ plugins { kotlin { sourceSets { - jvmMain { + commonMain { dependencies { api(projects.krpc.krpcServer) api(projects.krpc.krpcKtor.krpcKtorCore) diff --git a/krpc/krpc-ktor/krpc-ktor-server/gradle.properties b/krpc/krpc-ktor/krpc-ktor-server/gradle.properties deleted file mode 100644 index 58d0f9459..000000000 --- a/krpc/krpc-ktor/krpc-ktor-server/gradle.properties +++ /dev/null @@ -1,6 +0,0 @@ -# -# Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. -# - -kotlinx.rpc.excludeJs=true -kotlinx.rpc.excludeNative=true diff --git a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt similarity index 93% rename from krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt rename to krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt index 4f5922d1b..41ac1076c 100644 --- a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt +++ b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/Krpc.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.ktor.server diff --git a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt similarity index 97% rename from krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt rename to krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt index 0647529b1..efff16c5e 100644 --- a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt +++ b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KrpcRoute.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.ktor.server diff --git a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt similarity index 86% rename from krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt rename to krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt index 11431d831..8bba63699 100644 --- a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt +++ b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorKrpcServer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.ktor.server diff --git a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt similarity index 96% rename from krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt rename to krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt index db259b872..927e61a67 100644 --- a/krpc/krpc-ktor/krpc-ktor-server/src/jvmMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt +++ b/krpc/krpc-ktor/krpc-ktor-server/src/commonMain/kotlin/kotlinx/rpc/krpc/ktor/server/KtorServerDsl.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.ktor.server From 003a220f2f926c4ad6e48de21b752cc1c85390db Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Wed, 12 Mar 2025 13:36:51 +0100 Subject: [PATCH 2/5] Move krpc-test to commonMain --- krpc/krpc-test/build.gradle.kts | 14 +- krpc/krpc-test/src/commonMain/kotlin/Stub.kt | 8 - .../kotlinx/rpc/krpc/test/KrpcTestClient.kt | 2 +- .../kotlinx/rpc/krpc/test/KrpcTestServer.kt | 2 +- .../kotlinx/rpc/krpc/test/KrpcTestService.kt | 33 ++- .../rpc/krpc/test/KrpcTestServiceBackend.kt | 20 +- .../rpc/krpc/test/KrpcTransportTestBase.kt | 212 +++++++++--------- .../kotlin/kotlinx/rpc/krpc/test/Payloads.kt | 0 .../kotlin/kotlinx/rpc/krpc/test/TestClass.kt | 2 +- .../krpc/test/KrpcTestServiceBackend.js.kt | 9 + .../krpc/test/KrpcTestServiceBackend.jvm.kt | 9 + .../test/KrpcTestServiceBackend.native.kt | 13 ++ .../test/KrpcTestServiceBackend.wasmJs.kt | 9 + 13 files changed, 206 insertions(+), 127 deletions(-) delete mode 100644 krpc/krpc-test/src/commonMain/kotlin/Stub.kt rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt (90%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt (90%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt (86%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt (95%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt (81%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/Payloads.kt (100%) rename krpc/krpc-test/src/{jvmMain => commonMain}/kotlin/kotlinx/rpc/krpc/test/TestClass.kt (90%) create mode 100644 krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.js.kt create mode 100644 krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.jvm.kt create mode 100644 krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.native.kt create mode 100644 krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.wasmJs.kt diff --git a/krpc/krpc-test/build.gradle.kts b/krpc/krpc-test/build.gradle.kts index 8c6fa361f..deb9c3ba8 100644 --- a/krpc/krpc-test/build.gradle.kts +++ b/krpc/krpc-test/build.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode @@ -22,11 +22,7 @@ kotlin { // Workaround for // KLIB resolver: Could not find "org.jetbrains.kotlinx:atomicfu" api(libs.atomicfu) - } - } - jvmMain { - dependencies { api(projects.krpc.krpcCore) api(projects.krpc.krpcServer) api(projects.krpc.krpcClient) @@ -35,6 +31,12 @@ kotlin { implementation(libs.serialization.core) implementation(libs.kotlin.test) + implementation(libs.coroutines.test) + } + } + + jvmMain { + dependencies { implementation(libs.kotlin.test.junit) } } @@ -72,7 +74,7 @@ tasks.named("clean") { delete(resourcesPath.walk().filter { it.isFile && it.extension == tmpExt }.toList()) } -tasks.create("moveToGold") { +tasks.register("moveToGold") { doLast { resourcesPath.walk().forEach { if (it.isFile && it.extension == tmpExt) { diff --git a/krpc/krpc-test/src/commonMain/kotlin/Stub.kt b/krpc/krpc-test/src/commonMain/kotlin/Stub.kt deleted file mode 100644 index 2ebbf3513..000000000 --- a/krpc/krpc-test/src/commonMain/kotlin/Stub.kt +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -@file:Suppress("detekt.MissingPackageDeclaration") - -@Suppress("unused") -internal class Stub diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt similarity index 90% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt index f2ccc1f42..5799f4328 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestClient.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt similarity index 90% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt index 5176f0913..24c03069e 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServer.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt similarity index 86% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt index b4d31f729..6a031a73d 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestService.kt @@ -11,8 +11,37 @@ import kotlinx.rpc.RemoteService import kotlinx.rpc.annotations.Rpc import kotlinx.serialization.Contextual import kotlinx.serialization.Serializable -import java.time.LocalDate -import java.time.LocalDateTime + +data class LocalDate( + val year: Int, + val month: Int, + val day: Int, +) { + override fun toString(): String { + return "$year-$month-$day" + } + + companion object { + fun parse(str: String): LocalDate = str.split('-').let { + LocalDate(it[0].toInt(), it[1].toInt(), it[2].toInt()) + } + } +} + +data class LocalDateTime( + val date: LocalDate, + val time: String, +) { + override fun toString(): String { + return "$date $time" + } + + companion object { + fun parse(str: String): LocalDateTime = str.split(' ').let { + LocalDateTime(LocalDate.parse(it[0]), it[1]) + } + } +} @Suppress("detekt.TooManyFunctions") @Rpc diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt similarity index 95% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt index 8f72e4056..a410ab9c2 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt @@ -7,9 +7,6 @@ package kotlinx.rpc.krpc.test import kotlinx.coroutines.* import kotlinx.coroutines.flow.* import kotlinx.serialization.Serializable -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter import kotlin.coroutines.CoroutineContext import kotlin.coroutines.resumeWithException import kotlin.test.assertContentEquals @@ -110,11 +107,18 @@ class KrpcTestServiceBackend(override val coroutineContext: CoroutineContext) : } override suspend fun nonSerializableClass(localDate: LocalDate): LocalDate { - return localDate.plusDays(1) + return LocalDate(localDate.year, localDate.month, localDate.day + 1) } override suspend fun nonSerializableClassWithSerializer(localDateTime: LocalDateTime): String { - return localDateTime.plusDays(1).format(DateTimeFormatter.ISO_DATE_TIME) + return LocalDateTime( + date = LocalDate( + year = localDateTime.date.year, + month = localDateTime.date.month, + day = localDateTime.date.day + 1, + ), + time = localDateTime.time, + ).toString() } override suspend fun incomingStreamSyncCollect(arg1: Flow): Int { @@ -240,9 +244,9 @@ class KrpcTestServiceBackend(override val coroutineContext: CoroutineContext) : override suspend fun throwsUNSTOPPABLEThrowable(message: String) { suspendCancellableCoroutine { continuation -> - Thread { + runThreadIfPossible { continuation.resumeWithException(Throwable(message)) - }.start() + } } } @@ -320,3 +324,5 @@ class KrpcTestServiceBackend(override val coroutineContext: CoroutineContext) : return state } } + +internal expect fun runThreadIfPossible(runner: () -> Unit) diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt similarity index 81% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt index c1c51759b..5ada1a2d0 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt @@ -6,9 +6,12 @@ package kotlinx.rpc.krpc.test +import kotlinx.atomicfu.atomic import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.* +import kotlinx.coroutines.sync.Semaphore +import kotlinx.coroutines.test.runTest import kotlinx.rpc.awaitFieldInitialization import kotlinx.rpc.krpc.KrpcTransport import kotlinx.rpc.krpc.rpcClientConfig @@ -25,16 +28,8 @@ import kotlinx.serialization.descriptors.SerialDescriptor import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.modules.SerializersModule -import org.junit.Assert.assertEquals -import org.junit.Rule -import org.junit.rules.Timeout -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.format.DateTimeFormatter -import java.util.concurrent.Semaphore -import java.util.concurrent.TimeUnit -import java.util.concurrent.atomic.AtomicBoolean import kotlin.coroutines.cancellation.CancellationException +import kotlin.jvm.JvmField import kotlin.test.* internal object LocalDateSerializer : KSerializer { @@ -44,11 +39,11 @@ internal object LocalDateSerializer : KSerializer { encoder: Encoder, value: LocalDate, ) { - encoder.encodeString(value.format(DateTimeFormatter.ISO_DATE)) + encoder.encodeString(value.toString()) } override fun deserialize(decoder: Decoder): LocalDate { - return LocalDate.parse(decoder.decodeString(), DateTimeFormatter.ISO_DATE) + return LocalDate.parse(decoder.decodeString()) } } @@ -59,11 +54,11 @@ internal object LocalDateTimeSerializer : KSerializer { encoder: Encoder, value: LocalDateTime, ) { - encoder.encodeString(value.format(DateTimeFormatter.ISO_DATE_TIME)) + encoder.encodeString(value.toString()) } override fun deserialize(decoder: Decoder): LocalDateTime { - return LocalDateTime.parse(decoder.decodeString(), DateTimeFormatter.ISO_DATE_TIME) + return LocalDateTime.parse(decoder.decodeString()) } } @@ -117,20 +112,16 @@ abstract class KrpcTransportTestBase { backend.cancel() } - @Rule - @JvmField - val globalTimeout: Timeout = Timeout.seconds(30) - @Test fun nonSuspend() { - runBlocking { + runTest { assertEquals(List(10) { it }, client.nonSuspendFlow().toList()) } } @Test fun nonSuspendErrorOnEmit() { - runBlocking { + runTest { val flow = client.nonSuspendFlowErrorOnReturn() assertFailsWith { flow.toList() @@ -140,7 +131,7 @@ abstract class KrpcTransportTestBase { @Test fun nonSuspendErrorOnReturn() { - runBlocking { + runTest { assertFailsWith { client.nonSuspendFlowErrorOnReturn().toList() } @@ -155,21 +146,21 @@ abstract class KrpcTransportTestBase { @Test fun returnType() { - runBlocking { + runTest { assertEquals("test", client.returnType()) } } @Test fun simpleWithParams() { - runBlocking { + runTest { assertEquals("name".reversed(), client.simpleWithParams("name")) } } @Test @Ignore // works on my machine issue – timeouts on TC - fun simpleWithParams100000() = runBlocking { + fun simpleWithParams100000() = runTest { repeat(100000) { assertEquals("name".reversed(), client.simpleWithParams("name")) } @@ -177,111 +168,113 @@ abstract class KrpcTransportTestBase { @Test fun genericReturnType() { - runBlocking { + runTest { assertEquals(listOf("hello", "world"), client.genericReturnType()) } } @Test fun nonSerializableParameter() { - runBlocking { - val localDate = LocalDate.of(2001, 8, 23) + runTest { + val localDate = LocalDate(2001, 8, 23) val resultDate = client.nonSerializableClass(localDate) - assertEquals(localDate.plusDays(1), resultDate) + assertEquals(LocalDate(2001, 8, 24), resultDate) - val localDateTime = LocalDateTime.of(2001, 8, 23, 0, 0) + val localDateTime = LocalDateTime(LocalDate(2001, 8, 23), "17:03") val resultDateTime = client.nonSerializableClassWithSerializer(localDateTime) - assertEquals(localDateTime.plusDays(1).format(DateTimeFormatter.ISO_DATE_TIME), resultDateTime) + + assertEquals( + LocalDateTime(LocalDate(2001, 8, 24), "17:03").toString(), + resultDateTime, + ) } } @Test - fun doubleGenericReturnType() { - val result = runBlocking { client.doubleGenericReturnType() } + fun doubleGenericReturnType() = runTest { + val result = client.doubleGenericReturnType() assertEquals(listOf(listOf("1", "2"), listOf("a", "b")), result) } @Test - fun paramsSingle() { - val result = runBlocking { client.paramsSingle("test") } + fun paramsSingle() = runTest { + val result = client.paramsSingle("test") assertEquals(Unit, result) } @Test - fun paramsDouble() { - val result = runBlocking { client.paramsDouble("test", "test2") } + fun paramsDouble() = runTest { + val result = client.paramsDouble("test", "test2") assertEquals(Unit, result) } @Test @Ignore - fun varargParams() { - val result = runBlocking { client.varargParams("test", "test2", "test3") } + fun varargParams() = runTest { + val result = client.varargParams("test", "test2", "test3") assertEquals(Unit, result) } @Test - fun genericParams() { - val result = runBlocking { client.genericParams(listOf("test", "test2", "test3")) } + fun genericParams() = runTest { + val result = client.genericParams(listOf("test", "test2", "test3")) assertEquals(Unit, result) } @Test - fun doubleGenericParams() { - val result = runBlocking { client.doubleGenericParams(listOf(listOf("test", "test2", "test3"))) } + fun doubleGenericParams() = runTest { + val result = client.doubleGenericParams(listOf(listOf("test", "test2", "test3"))) assertEquals(Unit, result) } @Test - fun mapParams() { - val result = runBlocking { client.mapParams(mapOf("key" to mapOf(1 to listOf("test", "test2", "test3")))) } + fun mapParams() = runTest { + val result = client.mapParams(mapOf("key" to mapOf(1 to listOf("test", "test2", "test3")))) assertEquals(Unit, result) } @Test - fun customType() { - val result = runBlocking { client.customType(TestClass()) } + fun customType() = runTest { + val result = client.customType(TestClass()) assertEquals(TestClass(), result) } @Test - open fun nullable() { - val result = runBlocking { client.nullable("test") } + open fun nullable() = runTest { + val result = client.nullable("test") assertEquals(TestClass(), result) - val result2 = runBlocking { client.nullable(null) } + val result2 = client.nullable(null) assertEquals(null, result2) } @Test - fun variance() { - val result = runBlocking { client.variance(TestList(), TestList2()) } - assertEquals(TestList(3), result) + fun variance() = runTest { + val result = client.variance(TestList(), TestList2()) + assertEquals(TestList(3), result) } @Test - fun incomingStreamSyncCollect() { - val result = runBlocking { - streamScoped { - client.incomingStreamSyncCollect(flowOf("test1", "test2", "test3")) - } + fun incomingStreamSyncCollect() = runTest { + val result = streamScoped { + client.incomingStreamSyncCollect(flowOf("test1", "test2", "test3")) } + assertEquals(3, result) } @Test - fun incomingStreamAsyncCollect() { - val result = runBlocking { - streamScoped { - client.incomingStreamAsyncCollect(flowOf("test1", "test2", "test3")) - } + fun incomingStreamAsyncCollect() = runTest { + val result = streamScoped { + client.incomingStreamAsyncCollect(flowOf("test1", "test2", "test3")) } + assertEquals(5, result) } @Test fun outgoingStream() { - runBlocking { + runTest { streamScoped { val result = client.outgoingStream() assertEquals(listOf("a", "b", "c"), result.toList(mutableListOf())) @@ -291,7 +284,7 @@ abstract class KrpcTransportTestBase { @Test fun bidirectionalStream() { - runBlocking { + runTest { streamScoped { val result = client.bidirectionalStream(flowOf("test1", "test2", "test3")) assertEquals( @@ -304,7 +297,7 @@ abstract class KrpcTransportTestBase { @Test fun streamInDataClass() { - runBlocking { + runTest { streamScoped { val result = client.streamInDataClass(payload()) assertEquals(8, result) @@ -314,7 +307,7 @@ abstract class KrpcTransportTestBase { @Test fun streamInStream() { - runBlocking { + runTest { streamScoped { val result = client.streamInStream(payloadStream()) assertEquals(30, result) @@ -324,7 +317,7 @@ abstract class KrpcTransportTestBase { @Test fun streamOutDataClass() { - runBlocking { + runTest { streamScoped { val result = client.streamOutDataClass() assertEquals("test0", result.payload) @@ -335,7 +328,7 @@ abstract class KrpcTransportTestBase { @Test fun streamOfStreamsInReturn() { - runBlocking { + runTest { streamScoped { val result = client.streamOfStreamsInReturn().map { it.toList(mutableListOf()) @@ -347,7 +340,7 @@ abstract class KrpcTransportTestBase { @Test fun streamOfPayloadsInReturn() { - runBlocking { + runTest { streamScoped { val result = client.streamOfPayloadsInReturn().map { it.stream.toList(mutableListOf()).joinToString() @@ -363,7 +356,7 @@ abstract class KrpcTransportTestBase { @Test fun streamInDataClassWithStream() { - runBlocking { + runTest { streamScoped { val result = client.streamInDataClassWithStream(payloadWithPayload()) assertEquals(5, result) @@ -373,7 +366,7 @@ abstract class KrpcTransportTestBase { @Test fun streamInStreamWithStream() { - runBlocking { + runTest { val result = streamScoped { client.streamInStreamWithStream(payloadWithPayloadStream()) } @@ -383,7 +376,7 @@ abstract class KrpcTransportTestBase { @Test fun returnPayloadWithPayload() { - runBlocking { + runTest { streamScoped { assertContentEquals(expectedPayloadWithPayload(10), client.returnPayloadWithPayload().collect()) } @@ -392,7 +385,7 @@ abstract class KrpcTransportTestBase { @Test fun returnFlowPayloadWithPayload() { - runBlocking { + runTest { streamScoped { client.returnFlowPayloadWithPayload().collectIndexed { index, payloadWithPayload -> assertContentEquals(expectedPayloadWithPayload(index), payloadWithPayload.collect()) @@ -403,7 +396,7 @@ abstract class KrpcTransportTestBase { @Test fun bidirectionalFlowOfPayloadWithPayload() { - runBlocking { + runTest { streamScoped { val result = client.bidirectionalFlowOfPayloadWithPayload( flow { @@ -424,7 +417,7 @@ abstract class KrpcTransportTestBase { @Test fun bidirectionalAsyncStream() { - runBlocking { + runTest { streamScoped { val flow = MutableSharedFlow(1) val result = client.echoStream(flow.take(10)) @@ -444,7 +437,7 @@ abstract class KrpcTransportTestBase { @Test fun `RPC should be able to receive 100_000 ints in reasonable time`() { - runBlocking { + runTest { streamScoped { val n = 100_000 assertEquals(client.getNInts(n).last(), n) @@ -454,7 +447,7 @@ abstract class KrpcTransportTestBase { @Test fun `RPC should be able to receive 100_000 ints with batching in reasonable time`() { - runBlocking { + runTest { streamScoped { val n = 100_000 assertEquals(client.getNIntsBatched(n).last().last(), n) @@ -464,35 +457,47 @@ abstract class KrpcTransportTestBase { @Test open fun testByteArraySerialization() { - runBlocking { - client.bytes("hello".toByteArray()) + runTest { + client.bytes("hello".encodeToByteArray()) client.nullableBytes(null) - client.nullableBytes("hello".toByteArray()) + client.nullableBytes("hello".encodeToByteArray()) } } @Test @Suppress("detekt.TooGenericExceptionCaught") fun testExceptionSerializationAndPropagating() { - runBlocking { + runTest { try { client.throwsIllegalArgument("me") + fail("Exception expected") + } catch (e : AssertionError) { + throw e } catch (e: IllegalArgumentException) { assertEquals("me", e.message) } try { client.throwsSerializableWithMessageAndCause("me") + fail("Exception expected") + } catch (e : AssertionError) { + throw e } catch (e: KrpcTestServiceBackend.SerializableTestException) { assertEquals("me", e.message) assertEquals("cause: me", e.cause?.message) } try { client.throwsThrowable("me") + fail("Exception expected") + } catch (e : AssertionError) { + throw e } catch (e: Throwable) { assertEquals("me", e.message) } try { client.throwsUNSTOPPABLEThrowable("me") + fail("Exception expected") + } catch (e : AssertionError) { + throw e } catch (e: Throwable) { assertEquals("me", e.message) } @@ -501,7 +506,7 @@ abstract class KrpcTransportTestBase { @Test open fun testNullables() { - runBlocking { + runTest { assertEquals(1, client.nullableInt(1)) assertNull(client.nullable(null)) } @@ -509,7 +514,7 @@ abstract class KrpcTransportTestBase { @Test open fun testNullableLists() { - runBlocking { + runTest { assertNull(client.nullableList(null)) assertEquals(emptyList(), client.nullableList(emptyList())) @@ -519,7 +524,7 @@ abstract class KrpcTransportTestBase { @Test fun testServerCallCancellation() { - runBlocking { + runTest { val flag: Channel = Channel() val remote = launch { try { @@ -546,14 +551,18 @@ abstract class KrpcTransportTestBase { } } + class AtomicTest { + val atomic = atomic(true) + } + @Test fun `rpc continuation is called in the correct scope and doesn't block other rpcs`() { - runBlocking { + runTest { val inContinuation = Semaphore(1) - val running = AtomicBoolean(true) + val running = AtomicTest() // start a coroutine that block the thread after continuation - val c1 = async(Dispatchers.IO) { // make a rpc call + val c1 = async(Dispatchers.Default) { // make a rpc call client.answerToAnything("hello") // now we are in the continuation @@ -563,19 +572,20 @@ abstract class KrpcTransportTestBase { inContinuation.release() // let's block the thread - while (running.get()) { + while (running.atomic.value) { // do nothing } } // wait, till the Rpc continuation thread is blocked - assertTrue(inContinuation.tryAcquire(100, TimeUnit.MILLISECONDS)) + delay(100) + assertTrue(inContinuation.tryAcquire()) val c2 = async { // make a call // and make sure the continuation is executed, // even though another call's continuation has blocked its thread. client.answerToAnything("hello") - running.set(false) + running.atomic.compareAndSet(expect = true, update = false) } awaitAll(c1, c2) @@ -584,7 +594,7 @@ abstract class KrpcTransportTestBase { @Test fun testPlainFlowOfInts() { - runBlocking { + runTest { val flow = client.plainFlowOfInts.toList() assertEquals(List(5) { it }, flow) } @@ -592,7 +602,7 @@ abstract class KrpcTransportTestBase { @Test fun testPlainFlowOfFlowsOfInts() { - runBlocking { + runTest { val lists = client.plainFlowOfFlowsOfInts.map { it.toList() }.toList() @@ -603,7 +613,7 @@ abstract class KrpcTransportTestBase { @Test fun testPlainFlowOfFlowsOfFlowsOfInts() { - runBlocking { + runTest { val lists = client.plainFlowOfFlowsOfFlowsOfInts.map { it.map { i -> i.toList() }.toList() }.toList() @@ -614,7 +624,7 @@ abstract class KrpcTransportTestBase { @Test fun testSharedFlowOfInts() { - runBlocking { + runTest { val list1 = client.sharedFlowOfInts.take(5).toList() val list2 = client.sharedFlowOfInts.take(3).toList() @@ -625,7 +635,7 @@ abstract class KrpcTransportTestBase { @Test fun testSharedFlowOfFlowsOfInts() { - runBlocking { + runTest { val list1 = client.sharedFlowOfFlowsOfInts.take(5).map { it.take(5).toList() }.toList() @@ -641,7 +651,7 @@ abstract class KrpcTransportTestBase { @Test fun testSharedFlowOfFlowsOfFlowsOfInts() { - runBlocking { + runTest { val list1 = client.sharedFlowOfFlowsOfFlowsOfInts.take(5).map { it.take(5).map { i -> i.take(5).toList() }.toList() }.toList() @@ -657,7 +667,7 @@ abstract class KrpcTransportTestBase { @Test fun testStateFlowOfInts() { - runBlocking { + runTest { val flow = client.awaitFieldInitialization { stateFlowOfInts } assertEquals(-1, flow.value) @@ -670,7 +680,7 @@ abstract class KrpcTransportTestBase { @Test fun testStateFlowOfFlowsOfInts() { - runBlocking { + runTest { val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfInts } val flow2 = flow1.value @@ -685,7 +695,7 @@ abstract class KrpcTransportTestBase { @Test fun testStateFlowOfFlowsOfFlowsOfInts() { - runBlocking { + runTest { val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfFlowsOfInts } val flow2 = flow1.value val flow3 = flow2.value @@ -702,7 +712,7 @@ abstract class KrpcTransportTestBase { @Test fun testSharedFlowInFunction() { - runBlocking { + runTest { streamScoped { val flow = sharedFlowOfT { it } @@ -715,7 +725,7 @@ abstract class KrpcTransportTestBase { @Test fun testStateFlowInFunction() { - runBlocking { + runTest { streamScoped { val flow = stateFlowOfT { it } @@ -730,7 +740,7 @@ abstract class KrpcTransportTestBase { @Test fun testAwaitAllFields() { - runBlocking { + runTest { with(client.awaitFieldInitialization()) { assertEquals(-1, stateFlowOfInts.value) assertEquals(-1, stateFlowOfFlowsOfInts.value.value) diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/Payloads.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/Payloads.kt similarity index 100% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/Payloads.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/Payloads.kt diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt similarity index 90% rename from krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt rename to krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt index 44e171533..40bc98568 100644 --- a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/TestClass.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test diff --git a/krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.js.kt b/krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.js.kt new file mode 100644 index 000000000..5a01eb69d --- /dev/null +++ b/krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.js.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +actual inline fun runThreadIfPossible(runner: () -> Unit) { + runner() +} diff --git a/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.jvm.kt b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.jvm.kt new file mode 100644 index 000000000..9142c37fa --- /dev/null +++ b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.jvm.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +actual fun runThreadIfPossible(runner: () -> Unit) { + Thread(runner).start() +} diff --git a/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.native.kt b/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.native.kt new file mode 100644 index 000000000..72c450a8e --- /dev/null +++ b/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.native.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +import kotlin.native.concurrent.ObsoleteWorkersApi +import kotlin.native.concurrent.Worker + +@OptIn(ObsoleteWorkersApi::class) +actual fun runThreadIfPossible(runner: () -> Unit) { + Worker.start(errorReporting = true).executeAfter(0L, runner) +} diff --git a/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.wasmJs.kt b/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.wasmJs.kt new file mode 100644 index 000000000..5a01eb69d --- /dev/null +++ b/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.wasmJs.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +actual inline fun runThreadIfPossible(runner: () -> Unit) { + runner() +} From 3b2f7e8c579fd1af3936d39cbfd8d51273d9dafb Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Wed, 12 Mar 2025 18:36:06 +0100 Subject: [PATCH 3/5] Move krpc-test tests to commonTest --- .../rpc/descriptor/RpcServiceDescriptor.kt | 2 +- .../main/kotlin/util/ProjectKotlinConfig.kt | 18 +++--- .../src/main/kotlin/util/wasm.kt | 6 +- .../kotlinx/rpc/krpc/client/KrpcClient.kt | 8 +-- .../rpc/krpc/internal/KrpcConnector.kt | 22 ++++++- .../rpc/krpc/ktor/KtorTransportTest.kt | 3 +- krpc/krpc-test/build.gradle.kts | 12 ++-- krpc/krpc-test/gradle.properties | 6 ++ .../rpc/krpc/test/KrpcTestServiceBackend.kt | 3 + .../rpc/krpc/test/KrpcTransportTestBase.kt | 40 +++++++----- .../kotlinx/rpc/krpc/test/LocalTransport.kt | 2 +- .../rpc/krpc/test/LocalTransportTest.kt | 4 +- .../kotlinx/rpc/krpc/test/ProtocolTest.kt | 8 +-- .../kotlinx/rpc/krpc/test/ProtocolTestBase.kt | 3 +- .../kotlinx/rpc/krpc/test/SamplingService.kt | 2 +- .../kotlinx/rpc/krpc/test/TransportTest.kt | 62 +++++++++++++------ .../test/cancellation/CancellationService.kt | 0 .../test/cancellation/CancellationTest.kt | 9 ++- .../test/cancellation/CancellationToolkit.kt | 7 +-- .../test/cancellation/CancellationTest.js.kt | 9 +++ .../krpc/test/api/WireSamplingTestScope.kt | 4 +- .../test/cancellation/CancellationTest.jvm.kt | 9 +++ .../wire_dumps/0_6_0/callException_json.gold | 12 ++-- .../resources/wire_dumps/0_6_0/echo_json.gold | 12 ++-- .../wire_dumps/0_6_0/echo_protobuf.gold | 22 ++++--- .../cancellation/CancellationTest.native.kt | 13 ++++ .../cancellation/CancellationTest.wasmJs.kt | 9 +++ 27 files changed, 206 insertions(+), 101 deletions(-) create mode 100644 krpc/krpc-test/gradle.properties rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt (96%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt (92%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt (94%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt (97%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt (97%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt (76%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationService.kt (100%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt (99%) rename krpc/krpc-test/src/{jvmTest => commonTest}/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt (93%) create mode 100644 krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt create mode 100644 krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt create mode 100644 krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt create mode 100644 krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt diff --git a/core/src/commonMain/kotlin/kotlinx/rpc/descriptor/RpcServiceDescriptor.kt b/core/src/commonMain/kotlin/kotlinx/rpc/descriptor/RpcServiceDescriptor.kt index 4a2b138e4..aaa9b4fc2 100644 --- a/core/src/commonMain/kotlin/kotlinx/rpc/descriptor/RpcServiceDescriptor.kt +++ b/core/src/commonMain/kotlin/kotlinx/rpc/descriptor/RpcServiceDescriptor.kt @@ -88,6 +88,6 @@ public class RpcParameter(public val name: String, public val type: RpcType) @ExperimentalRpcApi public class RpcType(public val kType: KType) { override fun toString(): String { - return return kType.toString() + return kType.toString() } } diff --git a/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt b/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt index c2361a28f..aea92ee86 100644 --- a/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt +++ b/gradle-conventions/common/src/main/kotlin/util/ProjectKotlinConfig.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package util @@ -38,6 +38,7 @@ class ProjectKotlinConfig( jvm: Boolean = true, js: Boolean = true, wasmJs: Boolean = true, + wasmJsD8: Boolean = true, wasmWasi: Boolean = true, val native: Boolean = true, ) : Project by project { @@ -48,18 +49,18 @@ class ProjectKotlinConfig( private fun isIncluded( targetName: String, - kotlinVersion: KotlinVersion, - lookupTable: Map, + lookupTable: Map = targetsLookup, ): Boolean { return lookupTable[targetName]?.let { sinceKotlin -> sinceKotlin == FULLY_SUPPORTED_TARGET || sinceKotlin.kotlinVersionParsed() <= kotlinVersion } ?: false } - val jvm: Boolean by lazy { jvm && isIncluded("jvm", kotlinVersion, targetsLookup) } - val js: Boolean by lazy { js && isIncluded("js", kotlinVersion, targetsLookup) } - val wasmJs: Boolean by lazy { wasmJs && isIncluded("wasmJs", kotlinVersion, targetsLookup) } - val wasmWasi: Boolean by lazy { wasmWasi && isIncluded("wasmWasi", kotlinVersion, targetsLookup) } + val jvm: Boolean by lazy { jvm && isIncluded("jvm") } + val js: Boolean by lazy { js && isIncluded("js") } + val wasmJs: Boolean by lazy { wasmJs && isIncluded("wasmJs") } + val wasmJsD8: Boolean by lazy { wasmJsD8 && wasmJs } + val wasmWasi: Boolean by lazy { wasmWasi && isIncluded("wasmWasi") } private val nativeLookup by lazy { targetsLookup.filterKeys { key -> @@ -71,7 +72,6 @@ class ProjectKotlinConfig( .filter { targetFunction -> targetFunction.parameters.size == 1 && isIncluded( targetName = targetFunction.name, - kotlinVersion = kotlinVersion, lookupTable = nativeLookup, ) }.map { function -> @@ -84,6 +84,7 @@ fun Project.withKotlinConfig(configure: ProjectKotlinConfig.() -> Unit) { val excludeJvm: Boolean by optionalProperty() val excludeJs: Boolean by optionalProperty() val excludeWasmJs: Boolean by optionalProperty() + val excludeWasmJsD8: Boolean by optionalProperty() val excludeWasmWasi: Boolean by optionalProperty() val excludeNative: Boolean by optionalProperty() @@ -93,6 +94,7 @@ fun Project.withKotlinConfig(configure: ProjectKotlinConfig.() -> Unit) { jvm = !excludeJvm, js = !excludeJs, wasmJs = !excludeWasmJs, + wasmJsD8 = !excludeWasmJsD8, wasmWasi = !excludeWasmWasi, native = !excludeNative, ).configure() diff --git a/gradle-conventions/src/main/kotlin/util/wasm.kt b/gradle-conventions/src/main/kotlin/util/wasm.kt index b8633b529..0184877be 100644 --- a/gradle-conventions/src/main/kotlin/util/wasm.kt +++ b/gradle-conventions/src/main/kotlin/util/wasm.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package util @@ -23,7 +23,9 @@ fun ProjectKotlinConfig.configureWasm() { browser() nodejs() - d8() + if (wasmJsD8) { + d8() + } binaries.library() }.configurePublication() diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt index 665b35d98..d4f49021f 100644 --- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt +++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt @@ -258,9 +258,7 @@ public abstract class KrpcClient( val id = callCounter.incrementAndGet() - val dataTypeString = callable.dataType.toString() - - val callId = "$connectionId:$dataTypeString:$id" + val callId = "$connectionId:${callable.name}:$id" logger.trace { "start a call[$callId] ${callable.name}" } @@ -325,9 +323,7 @@ public abstract class KrpcClient( val callable = call.descriptor.getCallable(call.callableName) ?: error("Unexpected callable '${call.callableName}' for ${call.descriptor.fqName} service") - val dataTypeString = callable.dataType.toString() - - val callId = "$connectionId:$dataTypeString:$id" + val callId = "$connectionId:${callable.name}:$id" val channel = Channel() diff --git a/krpc/krpc-core/src/commonMain/kotlin/kotlinx/rpc/krpc/internal/KrpcConnector.kt b/krpc/krpc-core/src/commonMain/kotlin/kotlinx/rpc/krpc/internal/KrpcConnector.kt index 08bdcf327..a5fe988f0 100644 --- a/krpc/krpc-core/src/commonMain/kotlin/kotlinx/rpc/krpc/internal/KrpcConnector.kt +++ b/krpc/krpc-core/src/commonMain/kotlin/kotlinx/rpc/krpc/internal/KrpcConnector.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.internal @@ -154,9 +154,25 @@ public class KrpcConnector( if (waitForSubscribers) { waiting.getOrPut(message.getKey()) { mutableListOf() }.add(message) - logger.warn { + val reason = when (result) { + is HandlerResult.Failure -> { + "Unhandled exception while processing ${result.cause?.message}" + } + + is HandlerResult.NoSubscription -> { + "No service with key '${message.getKey()}' and '${message.serviceType}' type was registered." + + "Available: keys: [${subscriptions.keys.joinToString()}]" + } + + else -> { + "Unknown" + } + } + + logger.warn((result as? HandlerResult.Failure)?.cause) { "No registered service of ${message.serviceType} service type " + - "was able to process message at the moment. Waiting for new services." + "was able to process message at the moment. Waiting for new services." + + "Reason: $reason" } return diff --git a/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/krpc/ktor/KtorTransportTest.kt b/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/krpc/ktor/KtorTransportTest.kt index 21ae3d0c0..b7584d98a 100644 --- a/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/krpc/ktor/KtorTransportTest.kt +++ b/krpc/krpc-ktor/krpc-ktor-core/src/jvmTest/kotlin/kotlinx/rpc/krpc/ktor/KtorTransportTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ @file:Suppress("ExtractKtorModule") @@ -31,6 +31,7 @@ class NewServiceImpl( override val coroutineContext: CoroutineContext, private val call: ApplicationCall, ) : NewService { + @Suppress("UastIncorrectHttpHeaderInspection") override suspend fun echo(value: String): String { assertEquals("test-header", call.request.headers["TestHeader"]) return value diff --git a/krpc/krpc-test/build.gradle.kts b/krpc/krpc-test/build.gradle.kts index deb9c3ba8..ef8f05dbe 100644 --- a/krpc/krpc-test/build.gradle.kts +++ b/krpc/krpc-test/build.gradle.kts @@ -41,7 +41,7 @@ kotlin { } } - jvmTest { + commonTest { dependencies { implementation(projects.krpc.krpcTest) implementation(projects.krpc.krpcSerialization.krpcSerializationJson) @@ -49,12 +49,16 @@ kotlin { implementation(projects.krpc.krpcSerialization.krpcSerializationProtobuf) implementation(projects.krpc.krpcLogging) + implementation(libs.coroutines.test) + implementation(libs.kotlin.reflect) + } + } + + jvmTest { + dependencies { implementation(libs.slf4j.api) implementation(libs.logback.classic) - - implementation(libs.coroutines.test) implementation(libs.coroutines.debug) - implementation(libs.kotlin.reflect) } } } diff --git a/krpc/krpc-test/gradle.properties b/krpc/krpc-test/gradle.properties new file mode 100644 index 000000000..825c4ae92 --- /dev/null +++ b/krpc/krpc-test/gradle.properties @@ -0,0 +1,6 @@ +# +# Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. +# + +# tests fail with some obscure reason +kotlinx.rpc.excludeWasmJsD8=true diff --git a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt index a410ab9c2..f47ac6bba 100644 --- a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTestServiceBackend.kt @@ -125,11 +125,14 @@ class KrpcTestServiceBackend(override val coroutineContext: CoroutineContext) : return arg1.count() } + val incomingStreamAsyncCollectLatch = CompletableDeferred() + @OptIn(DelicateCoroutinesApi::class) override suspend fun incomingStreamAsyncCollect(arg1: Flow): Int { @Suppress("detekt.GlobalCoroutineUsage") GlobalScope.launch { assertContentEquals(listOf("test1", "test2", "test3"), arg1.toList()) + incomingStreamAsyncCollectLatch.complete(Unit) } return 5 } diff --git a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt index 5ada1a2d0..9de2309c6 100644 --- a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt @@ -29,7 +29,6 @@ import kotlinx.serialization.encoding.Decoder import kotlinx.serialization.encoding.Encoder import kotlinx.serialization.modules.SerializersModule import kotlin.coroutines.cancellation.CancellationException -import kotlin.jvm.JvmField import kotlin.test.* internal object LocalDateSerializer : KSerializer { @@ -98,11 +97,16 @@ abstract class KrpcTransportTestBase { private lateinit var backend: KrpcServer private lateinit var client: KrpcTestService + private lateinit var server: KrpcTestServiceBackend @BeforeTest fun start() { backend = KrpcTestServer(serverConfig, serverTransport) - backend.registerService { KrpcTestServiceBackend(it) } + backend.registerService { ctx -> + KrpcTestServiceBackend(ctx).also { + server = it + } + } client = KrpcTestClient(clientConfig, clientTransport).withService() } @@ -123,7 +127,7 @@ abstract class KrpcTransportTestBase { fun nonSuspendErrorOnEmit() { runTest { val flow = client.nonSuspendFlowErrorOnReturn() - assertFailsWith { + assertFails { flow.toList() } } @@ -132,7 +136,7 @@ abstract class KrpcTransportTestBase { @Test fun nonSuspendErrorOnReturn() { runTest { - assertFailsWith { + assertFails { client.nonSuspendFlowErrorOnReturn().toList() } } @@ -240,12 +244,14 @@ abstract class KrpcTransportTestBase { } @Test - open fun nullable() = runTest { - val result = client.nullable("test") - assertEquals(TestClass(), result) + open fun nullable() { + runTest { + val result = client.nullable("test") + assertEquals(TestClass(), result) - val result2 = client.nullable(null) - assertEquals(null, result2) + val result2 = client.nullable(null) + assertEquals(null, result2) + } } @Test @@ -266,7 +272,9 @@ abstract class KrpcTransportTestBase { @Test fun incomingStreamAsyncCollect() = runTest { val result = streamScoped { - client.incomingStreamAsyncCollect(flowOf("test1", "test2", "test3")) + client.incomingStreamAsyncCollect(flowOf("test1", "test2", "test3")).also { + server.incomingStreamAsyncCollectLatch.await() + } } assertEquals(5, result) @@ -470,24 +478,24 @@ abstract class KrpcTransportTestBase { runTest { try { client.throwsIllegalArgument("me") - fail("Exception expected") + fail("Exception expected: throwsIllegalArgument") } catch (e : AssertionError) { throw e - } catch (e: IllegalArgumentException) { + } catch (e: Throwable) { assertEquals("me", e.message) } try { client.throwsSerializableWithMessageAndCause("me") - fail("Exception expected") + fail("Exception expected: throwsSerializableWithMessageAndCause") } catch (e : AssertionError) { throw e - } catch (e: KrpcTestServiceBackend.SerializableTestException) { + } catch (e: Throwable) { assertEquals("me", e.message) assertEquals("cause: me", e.cause?.message) } try { client.throwsThrowable("me") - fail("Exception expected") + fail("Exception expected: throwsThrowable") } catch (e : AssertionError) { throw e } catch (e: Throwable) { @@ -495,7 +503,7 @@ abstract class KrpcTransportTestBase { } try { client.throwsUNSTOPPABLEThrowable("me") - fail("Exception expected") + fail("Exception expected: throwsUNSTOPPABLEThrowable") } catch (e : AssertionError) { throw e } catch (e: Throwable) { diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt similarity index 96% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt index 4250b105b..d4cda5500 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransport.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt similarity index 92% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt index 02e8c1cd3..55fdc3cd4 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt @@ -1,9 +1,11 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test +import kotlinx.coroutines.test.TestResult +import kotlinx.coroutines.test.runTest import kotlinx.rpc.krpc.KrpcTransport import kotlinx.rpc.krpc.serialization.KrpcSerialFormatConfiguration import kotlinx.rpc.krpc.serialization.cbor.cbor diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt similarity index 94% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt index e78423121..974277e81 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTest.kt @@ -1,10 +1,9 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test -import junit.framework.TestCase.assertEquals import kotlinx.coroutines.launch import kotlinx.rpc.krpc.KrpcTransportMessage import kotlinx.rpc.krpc.internal.KrpcPlugin @@ -12,8 +11,9 @@ import kotlinx.rpc.krpc.rpcClientConfig import kotlinx.rpc.krpc.rpcServerConfig import kotlinx.rpc.krpc.serialization.protobuf.protobuf import kotlinx.serialization.ExperimentalSerializationApi -import org.junit.Test +import kotlin.test.Test import kotlin.test.assertContentEquals +import kotlin.test.assertEquals @Suppress("detekt.MaxLineLength") @OptIn(ExperimentalSerializationApi::class) @@ -72,7 +72,7 @@ class ProtocolTest : ProtocolTestBase() { // callId changes here are always compatible val serverResponseMessage = KrpcTransportMessage.StringMessage( - "{\"type\":\"org.jetbrains.krpc.RPCMessage.CallSuccess\",\"callId\":\"$connectionId:kotlinx.rpc.krpc.test.ProtocolTestService.`\$rpcServiceStub`.`sendRequest\$rpcMethod`:1\",\"serviceType\":\"kotlinx.rpc.krpc.test.ProtocolTestService\",\"data\":\"{}\"}" + "{\"type\":\"org.jetbrains.krpc.RPCMessage.CallSuccess\",\"callId\":\"$connectionId:sendRequest:1\",\"serviceType\":\"kotlinx.rpc.krpc.test.ProtocolTestService\",\"data\":\"{}\"}" ) transport.server.send(serverResponseMessage) diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt similarity index 97% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt index e84a37f44..f1388db8d 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/ProtocolTestBase.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test @@ -27,7 +27,6 @@ import kotlinx.serialization.BinaryFormat import kotlin.coroutines.CoroutineContext abstract class ProtocolTestBase { - @Suppress("RedundantUnitReturnType") protected fun runTest( clientConfig: KrpcConfig.Client = rpcClientConfig { serialization { diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt similarity index 97% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt index 998e87975..54267498e 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/SamplingService.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ // NOTE: preserve package for compatibility tests diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt similarity index 76% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt index 3607bce66..63b7ebc58 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/TransportTest.kt @@ -1,22 +1,28 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test -import junit.framework.TestCase.assertEquals +import kotlinx.atomicfu.atomic import kotlinx.coroutines.* +import kotlinx.coroutines.test.TestResult +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runTest import kotlinx.rpc.* import kotlinx.rpc.annotations.Rpc import kotlinx.rpc.krpc.KrpcConfigBuilder +import kotlinx.rpc.krpc.internal.logging.CommonLogger +import kotlinx.rpc.krpc.internal.logging.DumpLogger +import kotlinx.rpc.krpc.internal.logging.DumpLoggerContainer import kotlinx.rpc.krpc.rpcClientConfig import kotlinx.rpc.krpc.rpcServerConfig import kotlinx.rpc.krpc.serialization.json.json -import java.util.concurrent.atomic.AtomicInteger import kotlin.coroutines.CoroutineContext import kotlin.test.Ignore import kotlin.test.Test -import kotlin.test.assertFailsWith +import kotlin.test.assertEquals +import kotlin.test.assertFails import kotlin.test.assertTrue @Rpc @@ -30,7 +36,7 @@ interface Second : RemoteService { } class EchoImpl(override val coroutineContext: CoroutineContext) : Echo { - val received = AtomicInteger() + val received = atomic(0) override suspend fun echo(message: String): String { received.incrementAndGet() @@ -39,7 +45,7 @@ class EchoImpl(override val coroutineContext: CoroutineContext) : Echo { } class SecondServer(override val coroutineContext: CoroutineContext) : Second { - val received = AtomicInteger() + val received = atomic(0) override suspend fun second(message: String): String { received.incrementAndGet() @@ -72,13 +78,29 @@ class TransportTest { return KrpcTestServer(serverConfig, localTransport.server) } + private fun runTest(block: suspend TestScope.() -> Unit): TestResult = kotlinx.coroutines.test.runTest { + val logger = CommonLogger.logger("TransportTest") + + DumpLoggerContainer.set(object : DumpLogger { + override val isEnabled: Boolean = true + + override fun dump(vararg tags: String, message: () -> String) { + logger.info { "${tags.joinToString(" ") { "[$it]" }} ${message()}" } + } + }) + + block() + + DumpLoggerContainer.set(null) + } + @Test - fun testUsingWrongService(): Unit = runBlocking { + fun testUsingWrongService() = runTest { val transports = LocalTransport() val client = clientOf(transports).withService() val result = async { - assertFailsWith { + assertFails { client.simpleWithParams("foo") } } @@ -97,7 +119,7 @@ class TransportTest { } @Test - fun testLateConnect() = runBlocking { + fun testLateConnect() = runTest { val transports = LocalTransport() val client = clientOf(transports).withService() @@ -110,13 +132,13 @@ class TransportTest { val echoServices = server.registerServiceAndReturn { EchoImpl(it) } assertEquals("foo", result.await()) - assertEquals(1, echoServices.single().received.get()) + assertEquals(1, echoServices.single().received.value) server.cancel() } @Test - fun testLateConnectWithManyCalls() = runBlocking { + fun testLateConnectWithManyCalls() = runTest { val transports = LocalTransport() val client = clientOf(transports).withService() @@ -131,13 +153,13 @@ class TransportTest { val response = result.awaitAll() assertTrue { response.all { it == "foo" } } - assertEquals(10, echoServices.single().received.get()) + assertEquals(10, echoServices.single().received.value) server.cancel() } @Test - fun testLateConnectWithManyServices() = runBlocking { + fun testLateConnectWithManyServices() = runTest { val transports = LocalTransport() val client = clientOf(transports) @@ -154,14 +176,14 @@ class TransportTest { val response = result.awaitAll() assertTrue { response.all { it == "foo" } } - assertEquals(10, echoServices.sumOf { it.received.get() }) + assertEquals(10, echoServices.sumOf { it.received.value }) server.cancel() } @Test - fun testLateConnectWithManyCallsAndClients() = runBlocking { + fun testLateConnectWithManyCallsAndClients() = runTest { val transports = LocalTransport() val client = clientOf(transports) @@ -182,13 +204,13 @@ class TransportTest { val response = result.awaitAll().flatten() assertTrue { response.all { it == "foo" } } - assertEquals(100, echoServices.sumOf { it.received.get() }) + assertEquals(100, echoServices.sumOf { it.received.value }) server.cancel() } @Test - fun testConnectMultipleServicesOnSingleClient(): Unit = runBlocking { + fun testConnectMultipleServicesOnSingleClient() = runTest { val transports = LocalTransport() val client = clientOf(transports) @@ -208,13 +230,13 @@ class TransportTest { delay(1000) val echoServices = server.registerServiceAndReturn { EchoImpl(it) } assertEquals("foo", firstResult.await()) - assertEquals(1, echoServices.single().received.get()) + assertEquals(1, echoServices.single().received.value) echoServices.single().cancel() delay(1000) val secondServices = server.registerServiceAndReturn { SecondServer(it) } assertEquals("bar", secondResult.await()) - assertEquals(1, secondServices.single().received.get()) + assertEquals(1, secondServices.single().received.value) secondServices.single().cancel() server.cancel() @@ -222,7 +244,7 @@ class TransportTest { @Test @Ignore - fun testCancelFromClientToServer() = runBlocking { + fun testCancelFromClientToServer() = runTest { val transports = LocalTransport() val client = clientOf(transports).withService() diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationService.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationService.kt similarity index 100% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationService.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationService.kt diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt similarity index 99% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt index ab393d5d9..49943d7c3 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt @@ -8,6 +8,7 @@ import kotlinx.coroutines.* import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.toList +import kotlinx.coroutines.test.runTest import kotlinx.rpc.krpc.StreamScope import kotlinx.rpc.krpc.internal.STREAM_SCOPES_ENABLED import kotlinx.rpc.krpc.invokeOnStreamScopeCompletion @@ -286,7 +287,7 @@ class CancellationTest { @Test fun testNestedStreamScopesForbidden() { - runBlocking { + runTest { assertFailsWith { streamScoped { streamScoped { } } } @@ -682,8 +683,8 @@ class CancellationTest { } } } - firstDone.await() + requestJob.cancel("Cancelled by test") requestJob.join() serverInstance().nonSuspendableFinished.await() @@ -701,7 +702,7 @@ class CancellationTest { val requestJob = processFlowAndLeaveUnusedForGC(firstDone, latch) firstDone.await() - System.gc() // hint GC to collect the flow + hintGC() // hint GC to collect the flow serverInstance().nonSuspendableFinished.await() assertEquals(false, serverInstance().nonSuspendableSecond) @@ -755,3 +756,5 @@ class CancellationTest { private suspend fun CancellationToolkit.stopAllAndJoin() = transport.coroutineContext.job.cancelAndJoin() } + +expect fun hintGC() diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt similarity index 93% rename from krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt rename to krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt index b16359a6c..430abff7e 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationToolkit.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test.cancellation @@ -21,15 +21,14 @@ import kotlinx.rpc.krpc.test.LocalTransport import kotlinx.rpc.registerService import kotlinx.rpc.withService -@Suppress("RedundantUnitReturnType") fun runCancellationTest(body: suspend CancellationToolkit.() -> Unit): TestResult { - runTest { + return runTest { CancellationToolkit(this).apply { body() } } } class CancellationToolkit(scope: CoroutineScope) : CoroutineScope by scope { - private val logger = CommonLogger.logger("[CancellationTest]") + private val logger = CommonLogger.logger("CancellationTest") init { DumpLoggerContainer.set(object : DumpLogger { diff --git a/krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt b/krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt new file mode 100644 index 000000000..1d7eb207a --- /dev/null +++ b/krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test.cancellation + +actual fun hintGC() { + // noop +} diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/api/WireSamplingTestScope.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/api/WireSamplingTestScope.kt index 6196dc68c..46f9b0578 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/api/WireSamplingTestScope.kt +++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/api/WireSamplingTestScope.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package kotlinx.rpc.krpc.test.api @@ -282,7 +282,7 @@ data class DumpLog( fun fromText(lines: List): List { return lines .map { it.trim() } - .filter { !it.startsWith("//") } + .filter { !it.startsWith("//") && it.isNotBlank() } .map { line -> val (prefix, log) = line.split("\$", limit = 2).map { it.trim() } val (role, phase) = prefix.split(" ") diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt new file mode 100644 index 000000000..843ed9d5e --- /dev/null +++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test.cancellation + +actual fun hintGC() { + System.gc() +} diff --git a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/callException_json.gold b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/callException_json.gold index 138b31556..8a3ceff5d 100644 --- a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/callException_json.gold +++ b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/callException_json.gold @@ -2,9 +2,9 @@ [Server] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765]} [Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765],"connectionId":1} [Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765],"connectionId":1} -[Client] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"callException","callType":"Method","data":"{}","connectionId":1,"serviceId":1} -[Server] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"callException","callType":"Method","data":"{}","connectionId":1,"serviceId":1} -[Server] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallException","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":null,"className":"java.lang.IllegalStateException"},"className":"java.lang.IllegalStateException"},"connectionId":1,"serviceId":1} -[Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1"}} -[Client] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallException","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":null,"className":"java.lang.IllegalStateException"},"className":"java.lang.IllegalStateException"},"connectionId":1,"serviceId":1} -[Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`callException$rpcMethod`:1"}} \ No newline at end of file +[Client] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:callException:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"callException","callType":"Method","data":"{}","connectionId":1,"serviceId":1} +[Server] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:callException:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"callException","callType":"Method","data":"{}","connectionId":1,"serviceId":1} +[Server] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallException","callId":"1:callException:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":null,"className":"java.lang.IllegalStateException"},"className":"java.lang.IllegalStateException"},"connectionId":1,"serviceId":1} +[Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:callException:1"}} +[Client] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallException","callId":"1:callException:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":{"toStringMessage":"java.lang.IllegalStateException: Server exception","message":"Server exception","stacktrace":[],"cause":null,"className":"java.lang.IllegalStateException"},"className":"java.lang.IllegalStateException"},"connectionId":1,"serviceId":1} +[Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:callException:1"}} diff --git a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_json.gold b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_json.gold index 0746c8b30..37c083ac4 100644 --- a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_json.gold +++ b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_json.gold @@ -2,9 +2,9 @@ [Server] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765]} [Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765],"connectionId":1} [Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake","supportedPlugins":[-32767,-32766,-32765],"connectionId":1} -[Client] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"echo","callType":"Method","data":"{\"arg1\":\"Hello\",\"data\":{\"data\":\"data\"}}","connectionId":1,"serviceId":1} -[Server] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"echo","callType":"Method","data":"{\"arg1\":\"Hello\",\"data\":{\"data\":\"data\"}}","connectionId":1,"serviceId":1} -[Server] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallSuccess","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","data":"{\"data\":\"data\"}","connectionId":1,"serviceId":1} -[Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1"}} -[Client] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallSuccess","callId":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","data":"{\"data\":\"data\"}","connectionId":1,"serviceId":1} -[Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1"}} \ No newline at end of file +[Client] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:echo:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"echo","callType":"Method","data":"{\"arg1\":\"Hello\",\"data\":{\"data\":\"data\"}}","connectionId":1,"serviceId":1} +[Server] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallData","callId":"1:echo:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","method":"echo","callType":"Method","data":"{\"arg1\":\"Hello\",\"data\":{\"data\":\"data\"}}","connectionId":1,"serviceId":1} +[Server] [Send] $ {"type":"org.jetbrains.krpc.RPCMessage.CallSuccess","callId":"1:echo:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","data":"{\"data\":\"data\"}","connectionId":1,"serviceId":1} +[Server] [Send] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:echo:1"}} +[Client] [Receive] $ {"type":"org.jetbrains.krpc.RPCMessage.CallSuccess","callId":"1:echo:1","serviceType":"org.jetbrains.krpc.test.api.util.SamplingService","data":"{\"data\":\"data\"}","connectionId":1,"serviceId":1} +[Client] [Receive] $ {"type":"org.jetbrains.krpc.internal.transport.RPCGenericMessage","connectionId":null,"pluginParams":{"-32767":"cancellation","-32766":"CANCELLATION_ACK","-32765":"1:echo:1"}} diff --git a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_protobuf.gold b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_protobuf.gold index b043a1ae5..d52bc3ab5 100644 --- a/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_protobuf.gold +++ b/krpc/krpc-test/src/jvmTest/resources/wire_dumps/0_6_0/echo_protobuf.gold @@ -6,13 +6,15 @@ [Server] [Send] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e52504350726f746f636f6c4d6573736167652e48616e647368616b651223088180feffffffffffff01088280feffffffffffff01088380feffffffffffff011001 // decoded: ?Borg.jetbrains.krpc.internal.transport.RPCProtocolMessage.Handshake?#??????????????????????????????????? [Client] [Receive] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e52504350726f746f636f6c4d6573736167652e48616e647368616b651223088180feffffffffffff01088280feffffffffffff01088380feffffffffffff011001 -// decoded: ??org.jetbrains.krpc.internal.transport.RPCMessage.CallDataBinary????W1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1?0org.jetbrains.krpc.test.api.util.SamplingService??echo ?*???Hello????data0?8? -[Client] [Send] $ 0a3f6f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c4461746142696e61727912a8010a57313a6f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963652e60247270635365727669636553747562602e606563686f247270634d6574686f64603a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a046563686f20002a0f0a0548656c6c6f12060a046461746130013801 -// decoded: ??org.jetbrains.krpc.internal.transport.RPCMessage.CallDataBinary????W1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1?0org.jetbrains.krpc.test.api.util.SamplingService??echo ?*???Hello????data0?8? -[Server] [Receive] $ 0a3f6f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c4461746142696e61727912a8010a57313a6f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963652e60247270635365727669636553747562602e606563686f247270634d6574686f64603a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a046563686f20002a0f0a0548656c6c6f12060a046461746130013801 -// decoded: ?Borg.jetbrains.krpc.internal.transport.RPCMessage.CallSuccessBinary????W1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1?0org.jetbrains.krpc.test.api.util.SamplingService????data ?(? -[Server] [Send] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c5375636365737342696e6172791297010a57313a6f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963652e60247270635365727669636553747562602e606563686f247270634d6574686f64603a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a060a046461746120012801 -// decoded: ?Borg.jetbrains.krpc.internal.transport.RPCMessage.CallSuccessBinary????W1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1?0org.jetbrains.krpc.test.api.util.SamplingService????data ?(? -[Client] [Receive] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c5375636365737342696e6172791297010a57313a6f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963652e60247270635365727669636553747562602e606563686f247270634d6574686f64603a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a060a046461746120012801 -// decoded: ?7org.jetbrains.krpc.internal.transport.RPCGenericMessage??????????????????cancellation???????????????CANCELLATION_ACK?d????????????W1:org.jetbrains.krpc.test.api.util.SamplingService.`$rpcServiceStub`.`echo$rpcMethod`:1 -[Server] [Send] $ 0a376f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e52504347656e657269634d65737361676512a0011219088180feffffffffffff01120c63616e63656c6c6174696f6e121d088280feffffffffffff01121043414e43454c4c4154494f4e5f41434b1264088380feffffffffffff011257313a6f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963652e60247270635365727669636553747562602e606563686f247270634d6574686f64603a31 \ No newline at end of file +// decoded: ??org.jetbrains.krpc.internal.transport.RPCMessage.CallDataBinary?Y??1:echo:1?0org.jetbrains.krpc.test.api.util.SamplingService??echo ?*???Hello????data0?8? +[Client] [Send] $ 0a3f6f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c4461746142696e61727912590a08313a6563686f3a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a046563686f20002a0f0a0548656c6c6f12060a046461746130013801 +// decoded: ??org.jetbrains.krpc.internal.transport.RPCMessage.CallDataBinary?Y??1:echo:1?0org.jetbrains.krpc.test.api.util.SamplingService??echo ?*???Hello????data0?8? +[Server] [Receive] $ 0a3f6f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c4461746142696e61727912590a08313a6563686f3a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a046563686f20002a0f0a0548656c6c6f12060a046461746130013801 +// decoded: ?Borg.jetbrains.krpc.internal.transport.RPCMessage.CallSuccessBinary?H??1:echo:1?0org.jetbrains.krpc.test.api.util.SamplingService????data ?(? +[Server] [Send] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c5375636365737342696e61727912480a08313a6563686f3a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a060a046461746120012801 +// decoded: ?7org.jetbrains.krpc.internal.transport.RPCGenericMessage?Q???????????????cancellation???????????????CANCELLATION_ACK???????????????1:echo:1 +[Server] [Send] $ 0a376f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e52504347656e657269634d65737361676512511219088180feffffffffffff01120c63616e63656c6c6174696f6e121d088280feffffffffffff01121043414e43454c4c4154494f4e5f41434b1215088380feffffffffffff011208313a6563686f3a31 +// decoded: ?Borg.jetbrains.krpc.internal.transport.RPCMessage.CallSuccessBinary?H??1:echo:1?0org.jetbrains.krpc.test.api.util.SamplingService????data ?(? +[Client] [Receive] $ 0a426f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e5250434d6573736167652e43616c6c5375636365737342696e61727912480a08313a6563686f3a3112306f72672e6a6574627261696e732e6b7270632e746573742e6170692e7574696c2e53616d706c696e67536572766963651a060a046461746120012801 +// decoded: ?7org.jetbrains.krpc.internal.transport.RPCGenericMessage?Q???????????????cancellation???????????????CANCELLATION_ACK???????????????1:echo:1 +[Client] [Receive] $ 0a376f72672e6a6574627261696e732e6b7270632e696e7465726e616c2e7472616e73706f72742e52504347656e657269634d65737361676512511219088180feffffffffffff01120c63616e63656c6c6174696f6e121d088280feffffffffffff01121043414e43454c4c4154494f4e5f41434b1215088380feffffffffffff011208313a6563686f3a31 diff --git a/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt b/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt new file mode 100644 index 000000000..02eba053d --- /dev/null +++ b/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test.cancellation + +import kotlin.native.runtime.GC +import kotlin.native.runtime.NativeRuntimeApi + +@OptIn(NativeRuntimeApi::class) +actual fun hintGC() { + GC.collect() +} diff --git a/krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt b/krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt new file mode 100644 index 000000000..1d7eb207a --- /dev/null +++ b/krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test.cancellation + +actual fun hintGC() { + // noop +} From 52f63cef62e1873bb3d4d8202188ec2e4abb5db4 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Wed, 12 Mar 2025 19:06:03 +0100 Subject: [PATCH 4/5] detekt --- .../src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt | 1 - .../kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt | 2 +- .../kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt | 2 -- .../kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt | 1 + 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt index d4f49021f..3a31eeacc 100644 --- a/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt +++ b/krpc/krpc-client/src/commonMain/kotlin/kotlinx/rpc/krpc/client/KrpcClient.kt @@ -7,7 +7,6 @@ package kotlinx.rpc.krpc.client import kotlinx.atomicfu.atomic import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.channels.ClosedReceiveChannelException import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.rpc.RpcCall diff --git a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt index 9de2309c6..086d49e20 100644 --- a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt @@ -473,7 +473,7 @@ abstract class KrpcTransportTestBase { } @Test - @Suppress("detekt.TooGenericExceptionCaught") + @Suppress("detekt.TooGenericExceptionCaught", "detekt.ThrowsCount") fun testExceptionSerializationAndPropagating() { runTest { try { diff --git a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt index 55fdc3cd4..47046aec4 100644 --- a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt @@ -4,8 +4,6 @@ package kotlinx.rpc.krpc.test -import kotlinx.coroutines.test.TestResult -import kotlinx.coroutines.test.runTest import kotlinx.rpc.krpc.KrpcTransport import kotlinx.rpc.krpc.serialization.KrpcSerialFormatConfiguration import kotlinx.rpc.krpc.serialization.cbor.cbor diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt index 843ed9d5e..d3f10f4fb 100644 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt +++ b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt @@ -4,6 +4,7 @@ package kotlinx.rpc.krpc.test.cancellation +@Suppress("detekt.ExplicitGarbageCollectionCall") actual fun hintGC() { System.gc() } From b1338a3cc5f7026ad2dbf56dea7a15296f2cfdc6 Mon Sep 17 00:00:00 2001 From: Alexander Sysoev Date: Mon, 17 Mar 2025 11:38:28 +0100 Subject: [PATCH 5/5] PR comments --- .../common/src/main/kotlin/util/JsTarget.kt | 4 +- krpc/krpc-test/build.gradle.kts | 10 + .../rpc/krpc/test/KrpcTransportTestBase.kt | 646 ++++++++---------- .../rpc/krpc/test/LocalTransportTest.kt | 10 +- .../test/cancellation/CancellationTest.kt | 14 +- .../krpc/test/KrpcTransportTestBase.js.kt} | 6 +- .../krpc/test/KrpcTransportTestBase.jvm.kt} | 6 +- .../test/cancellation/CancellationTest.jvm.kt | 10 - .../krpc/test/KrpcTransportTestBase.native.kt | 7 + .../cancellation/CancellationTest.native.kt | 13 - .../krpc/test/KrpcTransportTestBase.wasmJs.kt | 7 + 11 files changed, 328 insertions(+), 405 deletions(-) rename krpc/krpc-test/src/{jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt => jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.js.kt} (62%) rename krpc/krpc-test/src/{wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt => jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.jvm.kt} (62%) delete mode 100644 krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt create mode 100644 krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.native.kt delete mode 100644 krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt create mode 100644 krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.wasmJs.kt diff --git a/gradle-conventions/common/src/main/kotlin/util/JsTarget.kt b/gradle-conventions/common/src/main/kotlin/util/JsTarget.kt index 12187c011..2d480c488 100644 --- a/gradle-conventions/common/src/main/kotlin/util/JsTarget.kt +++ b/gradle-conventions/common/src/main/kotlin/util/JsTarget.kt @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ package util @@ -40,7 +40,7 @@ fun KotlinJsTargetDsl.configureJsAndWasmJsTasks() { nodejs { testTask { useMocha { - timeout = "10000" + timeout = "100s" } } } diff --git a/krpc/krpc-test/build.gradle.kts b/krpc/krpc-test/build.gradle.kts index ef8f05dbe..80e328f36 100644 --- a/krpc/krpc-test/build.gradle.kts +++ b/krpc/krpc-test/build.gradle.kts @@ -2,7 +2,9 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ +import com.osacky.doctor.internal.sysProperty import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode +import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest import util.applyAtomicfuPlugin import java.nio.file.Files @@ -78,6 +80,14 @@ tasks.named("clean") { delete(resourcesPath.walk().filter { it.isFile && it.extension == tmpExt }.toList()) } +tasks.withType { + onlyIf { + // for some reason browser tests don't wait for the test to complete and end immediately + // KRPC-166 + !targetName.orEmpty().endsWith("browser") + } +} + tasks.register("moveToGold") { doLast { resourcesPath.walk().forEach { diff --git a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt index 086d49e20..b1456e09f 100644 --- a/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt +++ b/krpc/krpc-test/src/commonMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.kt @@ -117,31 +117,26 @@ abstract class KrpcTransportTestBase { } @Test - fun nonSuspend() { - runTest { - assertEquals(List(10) { it }, client.nonSuspendFlow().toList()) - } + fun nonSuspend() = runTest { + assertEquals(List(10) { it }, client.nonSuspendFlow().toList()) } @Test - fun nonSuspendErrorOnEmit() { - runTest { - val flow = client.nonSuspendFlowErrorOnReturn() - assertFails { - flow.toList() - } + fun nonSuspendErrorOnEmit() = runTest { + val flow = client.nonSuspendFlowErrorOnReturn() + assertFails { + flow.toList() } } @Test - fun nonSuspendErrorOnReturn() { - runTest { - assertFails { - client.nonSuspendFlowErrorOnReturn().toList() - } + fun nonSuspendErrorOnReturn() = runTest { + assertFails { + client.nonSuspendFlowErrorOnReturn().toList() } } + @Test fun empty() { backend.cancel() @@ -149,17 +144,13 @@ abstract class KrpcTransportTestBase { } @Test - fun returnType() { - runTest { - assertEquals("test", client.returnType()) - } + fun returnType() = runTest { + assertEquals("test", client.returnType()) } @Test - fun simpleWithParams() { - runTest { - assertEquals("name".reversed(), client.simpleWithParams("name")) - } + fun simpleWithParams() = runTest { + assertEquals("name".reversed(), client.simpleWithParams("name")) } @Test @@ -171,27 +162,23 @@ abstract class KrpcTransportTestBase { } @Test - fun genericReturnType() { - runTest { - assertEquals(listOf("hello", "world"), client.genericReturnType()) - } + fun genericReturnType() = runTest { + assertEquals(listOf("hello", "world"), client.genericReturnType()) } @Test - fun nonSerializableParameter() { - runTest { - val localDate = LocalDate(2001, 8, 23) - val resultDate = client.nonSerializableClass(localDate) - assertEquals(LocalDate(2001, 8, 24), resultDate) + fun nonSerializableParameter() = runTest { + val localDate = LocalDate(2001, 8, 23) + val resultDate = client.nonSerializableClass(localDate) + assertEquals(LocalDate(2001, 8, 24), resultDate) - val localDateTime = LocalDateTime(LocalDate(2001, 8, 23), "17:03") - val resultDateTime = client.nonSerializableClassWithSerializer(localDateTime) + val localDateTime = LocalDateTime(LocalDate(2001, 8, 23), "17:03") + val resultDateTime = client.nonSerializableClassWithSerializer(localDateTime) - assertEquals( - LocalDateTime(LocalDate(2001, 8, 24), "17:03").toString(), - resultDateTime, - ) - } + assertEquals( + LocalDateTime(LocalDate(2001, 8, 24), "17:03").toString(), + resultDateTime, + ) } @Test @@ -244,14 +231,12 @@ abstract class KrpcTransportTestBase { } @Test - open fun nullable() { - runTest { - val result = client.nullable("test") - assertEquals(TestClass(), result) + open fun nullable() = runTest { + val result = client.nullable("test") + assertEquals(TestClass(), result) - val result2 = client.nullable(null) - assertEquals(null, result2) - } + val result2 = client.nullable(null) + assertEquals(null, result2) } @Test @@ -281,282 +266,242 @@ abstract class KrpcTransportTestBase { } @Test - fun outgoingStream() { - runTest { - streamScoped { - val result = client.outgoingStream() - assertEquals(listOf("a", "b", "c"), result.toList(mutableListOf())) - } + fun outgoingStream() = runTest { + streamScoped { + val result = client.outgoingStream() + assertEquals(listOf("a", "b", "c"), result.toList(mutableListOf())) } } @Test - fun bidirectionalStream() { - runTest { - streamScoped { - val result = client.bidirectionalStream(flowOf("test1", "test2", "test3")) - assertEquals( - listOf("test1".reversed(), "test2".reversed(), "test3".reversed()), - result.toList(mutableListOf()), - ) - } + fun bidirectionalStream() = runTest { + streamScoped { + val result = client.bidirectionalStream(flowOf("test1", "test2", "test3")) + assertEquals( + listOf("test1".reversed(), "test2".reversed(), "test3".reversed()), + result.toList(mutableListOf()), + ) } } @Test - fun streamInDataClass() { - runTest { - streamScoped { - val result = client.streamInDataClass(payload()) - assertEquals(8, result) - } + fun streamInDataClass() = runTest { + streamScoped { + val result = client.streamInDataClass(payload()) + assertEquals(8, result) } } @Test - fun streamInStream() { - runTest { - streamScoped { - val result = client.streamInStream(payloadStream()) - assertEquals(30, result) - } + fun streamInStream() = runTest { + streamScoped { + val result = client.streamInStream(payloadStream()) + assertEquals(30, result) } } @Test - fun streamOutDataClass() { - runTest { - streamScoped { - val result = client.streamOutDataClass() - assertEquals("test0", result.payload) - assertEquals(listOf("a0", "b0", "c0"), result.stream.toList(mutableListOf())) - } + fun streamOutDataClass() = runTest { + streamScoped { + val result = client.streamOutDataClass() + assertEquals("test0", result.payload) + assertEquals(listOf("a0", "b0", "c0"), result.stream.toList(mutableListOf())) } } @Test - fun streamOfStreamsInReturn() { - runTest { - streamScoped { - val result = client.streamOfStreamsInReturn().map { - it.toList(mutableListOf()) - }.toList(mutableListOf()) - assertEquals(listOf(listOf("a", "b", "c"), listOf("1", "2", "3")), result) - } + fun streamOfStreamsInReturn() = runTest { + streamScoped { + val result = client.streamOfStreamsInReturn().map { + it.toList(mutableListOf()) + }.toList(mutableListOf()) + assertEquals(listOf(listOf("a", "b", "c"), listOf("1", "2", "3")), result) } } @Test - fun streamOfPayloadsInReturn() { - runTest { - streamScoped { - val result = client.streamOfPayloadsInReturn().map { - it.stream.toList(mutableListOf()).joinToString() - }.toList(mutableListOf()).joinToString() - assertEquals( - "a0, b0, c0, a1, b1, c1, a2, b2, c2, a3, b3, c3, a4, " + - "b4, c4, a5, b5, c5, a6, b6, c6, a7, b7, c7, a8, b8, c8, a9, b9, c9", - result, - ) - } + fun streamOfPayloadsInReturn() = runTest { + streamScoped { + val result = client.streamOfPayloadsInReturn().map { + it.stream.toList(mutableListOf()).joinToString() + }.toList(mutableListOf()).joinToString() + assertEquals( + "a0, b0, c0, a1, b1, c1, a2, b2, c2, a3, b3, c3, a4, " + + "b4, c4, a5, b5, c5, a6, b6, c6, a7, b7, c7, a8, b8, c8, a9, b9, c9", + result, + ) } } @Test - fun streamInDataClassWithStream() { - runTest { - streamScoped { - val result = client.streamInDataClassWithStream(payloadWithPayload()) - assertEquals(5, result) - } + fun streamInDataClassWithStream() = runTest { + streamScoped { + val result = client.streamInDataClassWithStream(payloadWithPayload()) + assertEquals(5, result) } } @Test - fun streamInStreamWithStream() { - runTest { - val result = streamScoped { - client.streamInStreamWithStream(payloadWithPayloadStream()) - } - assertEquals(5, result) + fun streamInStreamWithStream() = runTest { + val result = streamScoped { + client.streamInStreamWithStream(payloadWithPayloadStream()) } + assertEquals(5, result) } @Test - fun returnPayloadWithPayload() { - runTest { - streamScoped { - assertContentEquals(expectedPayloadWithPayload(10), client.returnPayloadWithPayload().collect()) - } + fun returnPayloadWithPayload() = runTest { + streamScoped { + assertContentEquals(expectedPayloadWithPayload(10), client.returnPayloadWithPayload().collect()) } } @Test - fun returnFlowPayloadWithPayload() { - runTest { - streamScoped { - client.returnFlowPayloadWithPayload().collectIndexed { index, payloadWithPayload -> - assertContentEquals(expectedPayloadWithPayload(index), payloadWithPayload.collect()) - } + fun returnFlowPayloadWithPayload() = runTest { + streamScoped { + client.returnFlowPayloadWithPayload().collectIndexed { index, payloadWithPayload -> + assertContentEquals(expectedPayloadWithPayload(index), payloadWithPayload.collect()) } } } @Test - fun bidirectionalFlowOfPayloadWithPayload() { - runTest { - streamScoped { - val result = client.bidirectionalFlowOfPayloadWithPayload( - flow { - repeat(5) { - emit(payloadWithPayload(10)) - } - }, - ) + fun bidirectionalFlowOfPayloadWithPayload() = runTest { + streamScoped { + val result = client.bidirectionalFlowOfPayloadWithPayload( + flow { + repeat(5) { + emit(payloadWithPayload(10)) + } + }, + ) - val all = result.toList().onEach { - assertContentEquals(expectedPayloadWithPayload(10), it.collect()) - }.size + val all = result.toList().onEach { + assertContentEquals(expectedPayloadWithPayload(10), it.collect()) + }.size - assertEquals(5, all) - } + assertEquals(5, all) } } @Test - fun bidirectionalAsyncStream() { - runTest { - streamScoped { - val flow = MutableSharedFlow(1) - val result = client.echoStream(flow.take(10)) - launch { - var id = 0 - result.collect { - assertEquals(id, it) - id++ - flow.emit(id) - } + fun bidirectionalAsyncStream() = runTest { + streamScoped { + val flow = MutableSharedFlow(1) + val result = client.echoStream(flow.take(10)) + launch { + var id = 0 + result.collect { + assertEquals(id, it) + id++ + flow.emit(id) } - - flow.emit(0) } + + flow.emit(0) } } @Test - fun `RPC should be able to receive 100_000 ints in reasonable time`() { - runTest { - streamScoped { - val n = 100_000 - assertEquals(client.getNInts(n).last(), n) - } + fun `RPC should be able to receive 100_000 ints in reasonable time`() = runTest { + streamScoped { + val n = 100_000 + assertEquals(client.getNInts(n).last(), n) } } @Test - fun `RPC should be able to receive 100_000 ints with batching in reasonable time`() { - runTest { - streamScoped { - val n = 100_000 - assertEquals(client.getNIntsBatched(n).last().last(), n) - } + fun `RPC should be able to receive 100_000 ints with batching in reasonable time`() = runTest { + streamScoped { + val n = 100_000 + assertEquals(client.getNIntsBatched(n).last().last(), n) } } @Test - open fun testByteArraySerialization() { - runTest { - client.bytes("hello".encodeToByteArray()) - client.nullableBytes(null) - client.nullableBytes("hello".encodeToByteArray()) - } + open fun testByteArraySerialization() = runTest { + client.bytes("hello".encodeToByteArray()) + client.nullableBytes(null) + client.nullableBytes("hello".encodeToByteArray()) } @Test @Suppress("detekt.TooGenericExceptionCaught", "detekt.ThrowsCount") - fun testExceptionSerializationAndPropagating() { - runTest { - try { - client.throwsIllegalArgument("me") - fail("Exception expected: throwsIllegalArgument") - } catch (e : AssertionError) { - throw e - } catch (e: Throwable) { - assertEquals("me", e.message) - } - try { - client.throwsSerializableWithMessageAndCause("me") - fail("Exception expected: throwsSerializableWithMessageAndCause") - } catch (e : AssertionError) { - throw e - } catch (e: Throwable) { - assertEquals("me", e.message) - assertEquals("cause: me", e.cause?.message) - } - try { - client.throwsThrowable("me") - fail("Exception expected: throwsThrowable") - } catch (e : AssertionError) { - throw e - } catch (e: Throwable) { - assertEquals("me", e.message) - } - try { - client.throwsUNSTOPPABLEThrowable("me") - fail("Exception expected: throwsUNSTOPPABLEThrowable") - } catch (e : AssertionError) { - throw e - } catch (e: Throwable) { - assertEquals("me", e.message) - } + fun testExceptionSerializationAndPropagating() = runTest { + try { + client.throwsIllegalArgument("me") + fail("Exception expected: throwsIllegalArgument") + } catch (e : AssertionError) { + throw e + } catch (e: Throwable) { + assertEquals("me", e.message) + } + try { + client.throwsSerializableWithMessageAndCause("me") + fail("Exception expected: throwsSerializableWithMessageAndCause") + } catch (e : AssertionError) { + throw e + } catch (e: Throwable) { + assertEquals("me", e.message) + assertEquals("cause: me", e.cause?.message) + } + try { + client.throwsThrowable("me") + fail("Exception expected: throwsThrowable") + } catch (e : AssertionError) { + throw e + } catch (e: Throwable) { + assertEquals("me", e.message) + } + try { + client.throwsUNSTOPPABLEThrowable("me") + fail("Exception expected: throwsUNSTOPPABLEThrowable") + } catch (e : AssertionError) { + throw e + } catch (e: Throwable) { + assertEquals("me", e.message) } } @Test - open fun testNullables() { - runTest { - assertEquals(1, client.nullableInt(1)) - assertNull(client.nullable(null)) - } + open fun testNullables() = runTest { + assertEquals(1, client.nullableInt(1)) + assertNull(client.nullable(null)) } @Test - open fun testNullableLists() { - runTest { - assertNull(client.nullableList(null)) + open fun testNullableLists() = runTest { + assertNull(client.nullableList(null)) - assertEquals(emptyList(), client.nullableList(emptyList())) - assertEquals(listOf(1), client.nullableList(listOf(1))) - } + assertEquals(emptyList(), client.nullableList(emptyList())) + assertEquals(listOf(1), client.nullableList(listOf(1))) } @Test - fun testServerCallCancellation() { - runTest { - val flag: Channel = Channel() - val remote = launch { - try { - streamScoped { - client.delayForever().collect { - flag.send(it) - } + fun testServerCallCancellation() = runTest { + val flag: Channel = Channel() + val remote = launch { + try { + streamScoped { + client.delayForever().collect { + flag.send(it) } - } catch (e: CancellationException) { - throw e } + } catch (e: CancellationException) { + throw e + } - fail("Shall not pass here") - }.apply { - invokeOnCompletion { cause: Throwable? -> - if (cause != null && cause !is CancellationException) { - throw cause - } + fail("Shall not pass here") + }.apply { + invokeOnCompletion { cause: Throwable? -> + if (cause != null && cause !is CancellationException) { + throw cause } } - - flag.receive() - remote.cancelAndJoin() } + + flag.receive() + remote.cancelAndJoin() } class AtomicTest { @@ -564,196 +509,175 @@ abstract class KrpcTransportTestBase { } @Test - fun `rpc continuation is called in the correct scope and doesn't block other rpcs`() { - runTest { - val inContinuation = Semaphore(1) - val running = AtomicTest() - - // start a coroutine that block the thread after continuation - val c1 = async(Dispatchers.Default) { // make a rpc call - client.answerToAnything("hello") + fun `rpc continuation is called in the correct scope and doesn't block other rpcs`() = runTest { + if (isJs) { + println("Test is skipped on JS, because it doesn't support multiple threads.") + return@runTest + } - // now we are in the continuation - // important for test: don't use suspending primitives to signal it, - // as we want to make sure we have a blocked thread, - // when the second coroutine is launched - inContinuation.release() + val inContinuation = Semaphore(1) + val running = AtomicTest() - // let's block the thread - while (running.atomic.value) { - // do nothing - } - } + // start a coroutine that block the thread after continuation + val c1 = async(Dispatchers.Default) { // make a rpc call + client.answerToAnything("hello") - // wait, till the Rpc continuation thread is blocked - delay(100) - assertTrue(inContinuation.tryAcquire()) + // now we are in the continuation + // important for test: don't use suspending primitives to signal it, + // as we want to make sure we have a blocked thread, + // when the second coroutine is launched + inContinuation.release() - val c2 = async { // make a call - // and make sure the continuation is executed, - // even though another call's continuation has blocked its thread. - client.answerToAnything("hello") - running.atomic.compareAndSet(expect = true, update = false) + // let's block the thread + while (running.atomic.value) { + // do nothing } + } - awaitAll(c1, c2) + // wait, till the Rpc continuation thread is blocked + delay(100) + assertTrue(inContinuation.tryAcquire()) + + val c2 = async { // make a call + // and make sure the continuation is executed, + // even though another call's continuation has blocked its thread. + client.answerToAnything("hello") + running.atomic.compareAndSet(expect = true, update = false) } + + awaitAll(c1, c2) } @Test - fun testPlainFlowOfInts() { - runTest { - val flow = client.plainFlowOfInts.toList() - assertEquals(List(5) { it }, flow) - } + fun testPlainFlowOfInts() = runTest { + val flow = client.plainFlowOfInts.toList() + assertEquals(List(5) { it }, flow) } @Test - fun testPlainFlowOfFlowsOfInts() { - runTest { - val lists = client.plainFlowOfFlowsOfInts.map { - it.toList() - }.toList() + fun testPlainFlowOfFlowsOfInts() = runTest { + val lists = client.plainFlowOfFlowsOfInts.map { + it.toList() + }.toList() - assertEquals(List(5) { List(5) { it } }, lists) - } + assertEquals(List(5) { List(5) { it } }, lists) } @Test - fun testPlainFlowOfFlowsOfFlowsOfInts() { - runTest { - val lists = client.plainFlowOfFlowsOfFlowsOfInts.map { - it.map { i -> i.toList() }.toList() - }.toList() + fun testPlainFlowOfFlowsOfFlowsOfInts() = runTest { + val lists = client.plainFlowOfFlowsOfFlowsOfInts.map { + it.map { i -> i.toList() }.toList() + }.toList() - assertEquals(List(5) { List(5) { List(5) { it } } }, lists) - } + assertEquals(List(5) { List(5) { List(5) { it } } }, lists) } @Test - fun testSharedFlowOfInts() { - runTest { - val list1 = client.sharedFlowOfInts.take(5).toList() - val list2 = client.sharedFlowOfInts.take(3).toList() + fun testSharedFlowOfInts() = runTest { + val list1 = client.sharedFlowOfInts.take(5).toList() + val list2 = client.sharedFlowOfInts.take(3).toList() - assertEquals(List(5) { it }, list1) - assertEquals(List(3) { it }, list2) - } + assertEquals(List(5) { it }, list1) + assertEquals(List(3) { it }, list2) } @Test - fun testSharedFlowOfFlowsOfInts() { - runTest { - val list1 = client.sharedFlowOfFlowsOfInts.take(5).map { - it.take(5).toList() - }.toList() + fun testSharedFlowOfFlowsOfInts() = runTest { + val list1 = client.sharedFlowOfFlowsOfInts.take(5).map { + it.take(5).toList() + }.toList() - val list2 = client.sharedFlowOfFlowsOfInts.take(3).map { - it.take(3).toList() - }.toList() + val list2 = client.sharedFlowOfFlowsOfInts.take(3).map { + it.take(3).toList() + }.toList() - assertEquals(List(5) { List(5) { it } }, list1) - assertEquals(List(3) { List(3) { it } }, list2) - } + assertEquals(List(5) { List(5) { it } }, list1) + assertEquals(List(3) { List(3) { it } }, list2) } @Test - fun testSharedFlowOfFlowsOfFlowsOfInts() { - runTest { - val list1 = client.sharedFlowOfFlowsOfFlowsOfInts.take(5).map { - it.take(5).map { i -> i.take(5).toList() }.toList() - }.toList() + fun testSharedFlowOfFlowsOfFlowsOfInts() = runTest { + val list1 = client.sharedFlowOfFlowsOfFlowsOfInts.take(5).map { + it.take(5).map { i -> i.take(5).toList() }.toList() + }.toList() - val list2 = client.sharedFlowOfFlowsOfFlowsOfInts.take(3).map { - it.take(3).map { i -> i.take(3).toList() }.toList() - }.toList() + val list2 = client.sharedFlowOfFlowsOfFlowsOfInts.take(3).map { + it.take(3).map { i -> i.take(3).toList() }.toList() + }.toList() - assertEquals(List(5) { List(5) { List(5) { it } } }, list1) - assertEquals(List(3) { List(3) { List(3) { it } } }, list2) - } + assertEquals(List(5) { List(5) { List(5) { it } } }, list1) + assertEquals(List(3) { List(3) { List(3) { it } } }, list2) } @Test - fun testStateFlowOfInts() { - runTest { - val flow = client.awaitFieldInitialization { stateFlowOfInts } + fun testStateFlowOfInts() = runTest { + val flow = client.awaitFieldInitialization { stateFlowOfInts } - assertEquals(-1, flow.value) + assertEquals(-1, flow.value) - client.emitNextForStateFlowOfInts(42) + client.emitNextForStateFlowOfInts(42) - assertEquals(42, flow.first { it == 42 }) - } + assertEquals(42, flow.first { it == 42 }) } @Test - fun testStateFlowOfFlowsOfInts() { - runTest { - val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfInts } - val flow2 = flow1.value + fun testStateFlowOfFlowsOfInts() = runTest { + val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfInts } + val flow2 = flow1.value - assertEquals(-1, flow2.value) + assertEquals(-1, flow2.value) - client.emitNextForStateFlowOfFlowsOfInts(42) + client.emitNextForStateFlowOfFlowsOfInts(42) - assertEquals(42, flow2.first { it == 42 }) - assertEquals(42, flow1.first { it.value == 42 }.value) - } + assertEquals(42, flow2.first { it == 42 }) + assertEquals(42, flow1.first { it.value == 42 }.value) } @Test - fun testStateFlowOfFlowsOfFlowsOfInts() { - runTest { - val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfFlowsOfInts } - val flow2 = flow1.value - val flow3 = flow2.value + fun testStateFlowOfFlowsOfFlowsOfInts() = runTest { + val flow1 = client.awaitFieldInitialization { stateFlowOfFlowsOfFlowsOfInts } + val flow2 = flow1.value + val flow3 = flow2.value - assertEquals(-1, flow3.value) + assertEquals(-1, flow3.value) - client.emitNextForStateFlowOfFlowsOfFlowsOfInts(42) + client.emitNextForStateFlowOfFlowsOfFlowsOfInts(42) - assertEquals(42, flow3.first { it == 42 }) - assertEquals(42, flow2.first { it.value == 42 }.value) - assertEquals(42, flow1.first { it.value.value == 42 }.value.value) - } + assertEquals(42, flow3.first { it == 42 }) + assertEquals(42, flow2.first { it.value == 42 }.value) + assertEquals(42, flow1.first { it.value.value == 42 }.value.value) } @Test - fun testSharedFlowInFunction() { - runTest { - streamScoped { - val flow = sharedFlowOfT { it } + fun testSharedFlowInFunction() = runTest { + streamScoped { + val flow = sharedFlowOfT { it } - val state = client.sharedFlowInFunction(flow) + val state = client.sharedFlowInFunction(flow) - assertEquals(1, state.first { it == 1 }) - } + assertEquals(1, state.first { it == 1 }) } } @Test - fun testStateFlowInFunction() { - runTest { - streamScoped { - val flow = stateFlowOfT { it } + fun testStateFlowInFunction() = runTest { + streamScoped { + val flow = stateFlowOfT { it } - val state = client.stateFlowInFunction(flow) + val state = client.stateFlowInFunction(flow) - flow.emit(42) + flow.emit(42) - assertEquals(1, state.first { it == 1 }) - } + assertEquals(1, state.first { it == 1 }) } } @Test - fun testAwaitAllFields() { - runTest { - with(client.awaitFieldInitialization()) { - assertEquals(-1, stateFlowOfInts.value) - assertEquals(-1, stateFlowOfFlowsOfInts.value.value) - assertEquals(-1, stateFlowOfFlowsOfFlowsOfInts.value.value.value) - } + fun testAwaitAllFields() = runTest { + with(client.awaitFieldInitialization()) { + assertEquals(-1, stateFlowOfInts.value) + assertEquals(-1, stateFlowOfFlowsOfInts.value.value) + assertEquals(-1, stateFlowOfFlowsOfFlowsOfInts.value.value.value) } } @@ -761,3 +685,5 @@ abstract class KrpcTransportTestBase { fun expectedPayloadWithPayload(size: Int) = List(size) { listOf("a$it", "b$it", "c$it") } } } + +internal expect val isJs: Boolean diff --git a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt index 47046aec4..b8d033106 100644 --- a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/LocalTransportTest.kt @@ -4,6 +4,8 @@ package kotlinx.rpc.krpc.test +import kotlinx.coroutines.test.TestResult +import kotlinx.coroutines.test.runTest import kotlinx.rpc.krpc.KrpcTransport import kotlinx.rpc.krpc.serialization.KrpcSerialFormatConfiguration import kotlinx.rpc.krpc.serialization.cbor.cbor @@ -48,11 +50,11 @@ class ProtoBufLocalTransportTest : LocalTransportTest() { } // 'null' is not supported in ProtoBuf - override fun nullable() { } + override fun nullable(): TestResult = runTest { } - override fun testByteArraySerialization() { } + override fun testByteArraySerialization(): TestResult = runTest { } - override fun testNullables() { } + override fun testNullables(): TestResult = runTest { } - override fun testNullableLists() { } + override fun testNullableLists(): TestResult = runTest { } } diff --git a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt index 49943d7c3..3f690abeb 100644 --- a/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt +++ b/krpc/krpc-test/src/commonTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.kt @@ -286,11 +286,9 @@ class CancellationTest { } @Test - fun testNestedStreamScopesForbidden() { - runTest { - assertFailsWith { - streamScoped { streamScoped { } } - } + fun testNestedStreamScopesForbidden() = runTest { + assertFailsWith { + streamScoped { streamScoped { } } } } @@ -702,7 +700,9 @@ class CancellationTest { val requestJob = processFlowAndLeaveUnusedForGC(firstDone, latch) firstDone.await() - hintGC() // hint GC to collect the flow + // here, GC should collect the flow. + // so far, it works well locally and on TC, + // so, until it is flaky, we're good serverInstance().nonSuspendableFinished.await() assertEquals(false, serverInstance().nonSuspendableSecond) @@ -756,5 +756,3 @@ class CancellationTest { private suspend fun CancellationToolkit.stopAllAndJoin() = transport.coroutineContext.job.cancelAndJoin() } - -expect fun hintGC() diff --git a/krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt b/krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.js.kt similarity index 62% rename from krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt rename to krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.js.kt index 1d7eb207a..118af4f57 100644 --- a/krpc/krpc-test/src/jsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.js.kt +++ b/krpc/krpc-test/src/jsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.js.kt @@ -2,8 +2,6 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ -package kotlinx.rpc.krpc.test.cancellation +package kotlinx.rpc.krpc.test -actual fun hintGC() { - // noop -} +actual val isJs: Boolean = true diff --git a/krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.jvm.kt similarity index 62% rename from krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt rename to krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.jvm.kt index 1d7eb207a..ee108e9c0 100644 --- a/krpc/krpc-test/src/wasmJsTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.wasmJs.kt +++ b/krpc/krpc-test/src/jvmMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.jvm.kt @@ -2,8 +2,6 @@ * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. */ -package kotlinx.rpc.krpc.test.cancellation +package kotlinx.rpc.krpc.test -actual fun hintGC() { - // noop -} +actual val isJs: Boolean = false diff --git a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt b/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt deleted file mode 100644 index d3f10f4fb..000000000 --- a/krpc/krpc-test/src/jvmTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.jvm.kt +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.rpc.krpc.test.cancellation - -@Suppress("detekt.ExplicitGarbageCollectionCall") -actual fun hintGC() { - System.gc() -} diff --git a/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.native.kt b/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.native.kt new file mode 100644 index 000000000..ee108e9c0 --- /dev/null +++ b/krpc/krpc-test/src/nativeMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.native.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +actual val isJs: Boolean = false diff --git a/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt b/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt deleted file mode 100644 index 02eba053d..000000000 --- a/krpc/krpc-test/src/nativeTest/kotlin/kotlinx/rpc/krpc/test/cancellation/CancellationTest.native.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. - */ - -package kotlinx.rpc.krpc.test.cancellation - -import kotlin.native.runtime.GC -import kotlin.native.runtime.NativeRuntimeApi - -@OptIn(NativeRuntimeApi::class) -actual fun hintGC() { - GC.collect() -} diff --git a/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.wasmJs.kt b/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.wasmJs.kt new file mode 100644 index 000000000..118af4f57 --- /dev/null +++ b/krpc/krpc-test/src/wasmJsMain/kotlin/kotlinx/rpc/krpc/test/KrpcTransportTestBase.wasmJs.kt @@ -0,0 +1,7 @@ +/* + * Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license. + */ + +package kotlinx.rpc.krpc.test + +actual val isJs: Boolean = true