Skip to content

Commit 5f3e091

Browse files
authored
KRPC-129 Move compatibility tests from Toolbox to Kotlin RPC repo (#304)
1 parent ee5ab90 commit 5f3e091

File tree

18 files changed

+537
-1
lines changed

18 files changed

+537
-1
lines changed

krpc/krpc-test/build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5-
import com.osacky.doctor.internal.sysProperty
65
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
76
import org.jetbrains.kotlin.gradle.targets.js.testing.KotlinJsTest
87
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest

settings.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ includePublic(":krpc:krpc-ktor:krpc-ktor-server")
5959
includePublic(":krpc:krpc-ktor:krpc-ktor-client")
6060

6161
include(":tests")
62+
include(":tests:krpc-compatibility-tests")
6263

6364
val kotlinMasterBuild = providers.gradleProperty("kotlinx.rpc.kotlinMasterBuild").orNull == "true"
6465

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
6+
import util.applyAtomicfuPlugin
7+
8+
plugins {
9+
alias(libs.plugins.conventions.jvm)
10+
alias(libs.plugins.serialization)
11+
alias(libs.plugins.kotlinx.rpc)
12+
}
13+
14+
applyAtomicfuPlugin()
15+
16+
val main: SourceSet by sourceSets.getting
17+
val test: SourceSet by sourceSets.getting
18+
19+
val oldApi: SourceSet by sourceSets.creating {
20+
compileClasspath += main.output
21+
compileClasspath += test.compileClasspath
22+
runtimeClasspath += main.output
23+
runtimeClasspath += test.runtimeClasspath
24+
}
25+
26+
val newApi: SourceSet by sourceSets.creating {
27+
compileClasspath += main.output
28+
compileClasspath += test.compileClasspath
29+
runtimeClasspath += main.output
30+
runtimeClasspath += test.runtimeClasspath
31+
}
32+
33+
val compatibilityTestSourcesDir: File = project.layout.buildDirectory.dir("compatibilityTestSources").get().asFile
34+
35+
val copyOldToTestResources by tasks.register<Copy>("copyOldToTestResources") {
36+
dependsOn(oldApi.output)
37+
from(oldApi.output)
38+
into(compatibilityTestSourcesDir.resolve("old"))
39+
}
40+
41+
val copyNewToTestResources by tasks.register<Copy>("copyNewToTestResources") {
42+
dependsOn(newApi.output)
43+
from(newApi.output)
44+
into(compatibilityTestSourcesDir.resolve("new"))
45+
}
46+
47+
test.resources {
48+
srcDir(compatibilityTestSourcesDir)
49+
}
50+
51+
tasks.processTestResources.configure {
52+
dependsOn(copyOldToTestResources, copyNewToTestResources)
53+
}
54+
55+
dependencies {
56+
api(libs.atomicfu)
57+
58+
api(projects.krpc.krpcCore)
59+
api(projects.krpc.krpcServer)
60+
api(projects.krpc.krpcClient)
61+
62+
implementation(projects.krpc.krpcSerialization.krpcSerializationJson)
63+
64+
implementation(libs.serialization.core)
65+
implementation(libs.coroutines.test)
66+
implementation(libs.kotlin.test.junit5)
67+
implementation(libs.kotlin.reflect)
68+
69+
testImplementation(libs.slf4j.api)
70+
testImplementation(libs.logback.classic)
71+
testImplementation(libs.coroutines.debug)
72+
}
73+
74+
kotlin {
75+
explicitApi = ExplicitApiMode.Disabled
76+
}
77+
78+
tasks.test {
79+
useJUnitPlatform()
80+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.rpc.krpc.compatibility
6+
7+
import kotlinx.rpc.RpcClient
8+
9+
interface CompatibilityTest {
10+
fun getAllTests(): Map<String, suspend (RpcClient) -> Unit>
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package kotlinx.rpc.krpc.compatibility
6+
7+
import kotlinx.rpc.RpcServer
8+
9+
interface TestApiServer {
10+
fun serveAllInterfaces(rpcServer: RpcServer)
11+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlin.coroutines.CoroutineContext
10+
11+
@Rpc
12+
interface BarInterface : RemoteService {
13+
suspend fun get(): Unit
14+
suspend fun get2(): Unit
15+
}
16+
17+
class BarInterfaceImpl(override val coroutineContext: CoroutineContext) : BarInterface {
18+
override suspend fun get() {}
19+
20+
override suspend fun get2() {}
21+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlinx.serialization.Serializable
10+
import kotlin.coroutines.CoroutineContext
11+
12+
@Serializable
13+
data class Baz(val field: String, val field2: String = "")
14+
15+
@Rpc
16+
interface BazInterface : RemoteService {
17+
suspend fun get(): Baz
18+
}
19+
20+
class BazInterfaceImpl(override val coroutineContext: CoroutineContext) : BazInterface {
21+
override suspend fun get(): Baz = Baz("asd", "def")
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlinx.serialization.Serializable
10+
import kotlin.coroutines.CoroutineContext
11+
12+
@Serializable
13+
data class Foo(val field: String, val field2: String? = null)
14+
15+
@Rpc
16+
interface FooInterface : RemoteService {
17+
suspend fun get(): Foo
18+
}
19+
20+
class FooInterfaceImpl(override val coroutineContext: CoroutineContext) : FooInterface {
21+
override suspend fun get(): Foo {
22+
return Foo("", "")
23+
}
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package tests
6+
7+
import kotlinx.rpc.krpc.compatibility.TestApiServer
8+
import interfaces.BarInterface
9+
import interfaces.BarInterfaceImpl
10+
import interfaces.BazInterface
11+
import interfaces.BazInterfaceImpl
12+
import interfaces.FooInterface
13+
import interfaces.FooInterfaceImpl
14+
import kotlinx.rpc.RpcServer
15+
import kotlinx.rpc.registerService
16+
17+
@Suppress("unused")
18+
class ApiServer : TestApiServer {
19+
override fun serveAllInterfaces(rpcServer: RpcServer) {
20+
rpcServer.apply {
21+
registerService<FooInterface> { FooInterfaceImpl(it) }
22+
registerService<BarInterface> { BarInterfaceImpl(it) }
23+
registerService<BazInterface> { BazInterfaceImpl(it) }
24+
}
25+
}
26+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
@file:Suppress("FunctionName")
6+
7+
package tests
8+
9+
import kotlinx.rpc.krpc.compatibility.CompatibilityTest
10+
import interfaces.BarInterface
11+
import interfaces.BazInterface
12+
import interfaces.FooInterface
13+
import kotlinx.rpc.RpcClient
14+
import kotlinx.rpc.withService
15+
import kotlin.reflect.KCallable
16+
import kotlin.reflect.full.callSuspend
17+
import kotlin.test.assertEquals
18+
19+
@Suppress("unused")
20+
class CompatibilityTests : CompatibilityTest {
21+
override fun getAllTests(): Map<String, suspend (RpcClient) -> Unit> {
22+
return mapOf(
23+
this::`should work with older data class without nullable field`.toEntry(),
24+
this::`should work with older interface without method`.toEntry(),
25+
this::`should work with older data class without a field with default value`.toEntry(),
26+
)
27+
}
28+
29+
suspend fun `should work with older data class without nullable field`(rpcClient: RpcClient) {
30+
val service = rpcClient.withService<FooInterface>()
31+
val res = service.get()
32+
assertEquals("", res.field)
33+
assertEquals(null, res.field2)
34+
}
35+
36+
suspend fun `should work with older interface without method`(rpcClient: RpcClient) {
37+
val service = rpcClient.withService<BarInterface>()
38+
service.get()
39+
// Of course, we can't call the second method
40+
}
41+
42+
suspend fun `should work with older data class without a field with default value`(rpcClient: RpcClient) {
43+
val service = rpcClient.withService<BazInterface>()
44+
val res = service.get()
45+
assertEquals("asd", res.field)
46+
assertEquals("", res.field2)
47+
// Of course, we can't call the second method
48+
}
49+
50+
private fun KCallable<Unit>.toEntry(): Pair<String, suspend (RpcClient) -> Unit> {
51+
return name to { callSuspend(it) }
52+
}
53+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlin.coroutines.CoroutineContext
10+
11+
@Rpc
12+
interface BarInterface : RemoteService {
13+
suspend fun get()
14+
}
15+
16+
class BarInterfaceImpl(override val coroutineContext: CoroutineContext) : BarInterface {
17+
override suspend fun get() {}
18+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlinx.serialization.Serializable
10+
import kotlin.coroutines.CoroutineContext
11+
12+
@Serializable
13+
data class Baz(val field: String)
14+
15+
@Rpc
16+
interface BazInterface : RemoteService {
17+
suspend fun get(): Baz
18+
}
19+
20+
class BazInterfaceImpl(override val coroutineContext: CoroutineContext) : BazInterface {
21+
override suspend fun get(): Baz = Baz("asd")
22+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package interfaces
6+
7+
import kotlinx.rpc.RemoteService
8+
import kotlinx.rpc.annotations.Rpc
9+
import kotlinx.serialization.Serializable
10+
import kotlin.coroutines.CoroutineContext
11+
12+
@Serializable
13+
data class Foo(val field: String)
14+
15+
@Rpc
16+
interface FooInterface : RemoteService {
17+
suspend fun get(): Foo
18+
}
19+
20+
class FooInterfaceImpl(override val coroutineContext: CoroutineContext) : FooInterface {
21+
override suspend fun get(): Foo {
22+
return Foo("")
23+
}
24+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
3+
*/
4+
5+
package tests
6+
7+
import kotlinx.rpc.krpc.compatibility.TestApiServer
8+
import interfaces.BarInterface
9+
import interfaces.BarInterfaceImpl
10+
import interfaces.BazInterface
11+
import interfaces.BazInterfaceImpl
12+
import interfaces.FooInterface
13+
import interfaces.FooInterfaceImpl
14+
import kotlinx.rpc.RpcServer
15+
import kotlinx.rpc.registerService
16+
17+
@Suppress("unused")
18+
class ApiServer : TestApiServer {
19+
override fun serveAllInterfaces(rpcServer: RpcServer) {
20+
rpcServer.apply {
21+
registerService<FooInterface> { FooInterfaceImpl(it) }
22+
registerService<BarInterface> { BarInterfaceImpl(it) }
23+
registerService<BazInterface> { BazInterfaceImpl(it) }
24+
}
25+
}
26+
}

0 commit comments

Comments
 (0)