Skip to content

Commit 340838f

Browse files
committed
- Added grpc+protobuf tests
- Fixed WithCodec checker - MessageCodec now uses InputStream
1 parent 43f48b4 commit 340838f

File tree

65 files changed

+927
-659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+927
-659
lines changed

compiler-plugin/compiler-plugin-k2/src/main/kotlin/kotlinx/rpc/codegen/checkers/FirWithCodecDeclarationChecker.kt

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
package kotlinx.rpc.codegen.checkers
66

77
import kotlinx.rpc.codegen.FirRpcPredicates
8-
import kotlinx.rpc.codegen.FirVersionSpecificApiImpl.toClassSymbolVS
98
import kotlinx.rpc.codegen.checkers.diagnostics.FirGrpcDiagnostics
109
import kotlinx.rpc.codegen.common.RpcClassId
1110
import kotlinx.rpc.codegen.vsApi
@@ -20,7 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
2019
import org.jetbrains.kotlin.fir.declarations.getKClassArgument
2120
import org.jetbrains.kotlin.fir.extensions.predicateBasedProvider
2221
import org.jetbrains.kotlin.fir.resolve.defaultType
23-
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
22+
import org.jetbrains.kotlin.fir.resolve.getSuperTypes
2423
import org.jetbrains.kotlin.fir.symbols.impl.FirClassSymbol
2524
import org.jetbrains.kotlin.fir.types.ConeKotlinType
2625
import org.jetbrains.kotlin.fir.types.classId
@@ -55,9 +54,7 @@ object FirWithCodecDeclarationChecker {
5554
"for declaration: ${declaration.symbol.classId.asSingleFqName()}"
5655
)
5756

58-
val codecTargetClass = codecClassSymbol.findMessageCodecSuperType(context.session)
59-
.typeArguments.first().type
60-
?: error("Unexpected unresolved type argument for @WithCodec annotation")
57+
val codecTargetClass = codecClassSymbol.resolveMessageCodecTypeArgument(context.session)
6158

6259
if (codecTargetClass.classId != declaration.symbol.classId) {
6360
reporter.reportOn(
@@ -78,12 +75,13 @@ object FirWithCodecDeclarationChecker {
7875
}
7976
}
8077

81-
private fun FirClassSymbol<*>.findMessageCodecSuperType(session: FirSession): ConeKotlinType = vsApi {
82-
return resolvedSuperTypes.find {
83-
it.classId == RpcClassId.messageCodec
84-
} ?: resolvedSuperTypes.firstNotNullOf {
85-
it.toClassSymbolVS(session)?.findMessageCodecSuperType(session)
86-
}
78+
private fun FirClassSymbol<*>.resolveMessageCodecTypeArgument(session: FirSession): ConeKotlinType = vsApi {
79+
val superTypes = getSuperTypes(session, recursive = true, lookupInterfaces = true, substituteSuperTypes = true)
80+
81+
return superTypes
82+
.find { it.classId == RpcClassId.messageCodec }
83+
?.typeArguments?.single()?.type
84+
?: error("'MessageCodec' supertype not found for $classId")
8785
}
8886

8987
private val CODEC_ARGUMENT_NAME = Name.identifier("codec")

grpc/grpc-codec-kotlinx-serialization/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/kotlinx/serialization/KotlinxSerializationCodecResolver.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@ import kotlinx.io.readString
1111
import kotlinx.io.writeString
1212
import kotlinx.rpc.grpc.codec.MessageCodec
1313
import kotlinx.rpc.grpc.codec.MessageCodecResolver
14+
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
1415
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
1516
import kotlinx.serialization.BinaryFormat
1617
import kotlinx.serialization.KSerializer
1718
import kotlinx.serialization.SerialFormat
1819
import kotlinx.serialization.StringFormat
19-
import kotlinx.serialization.serializer
2020
import kotlinx.serialization.serializerOrNull
2121
import kotlin.reflect.KType
2222

@@ -36,8 +36,8 @@ public fun SerialFormat.asCodecResolver(): MessageCodecResolver =
3636
private class KotlinxSerializationCodec<T>(
3737
private val serializer: KSerializer<T>,
3838
private val serialFormat: SerialFormat,
39-
) : MessageCodec<T> {
40-
override fun encode(value: T): Source {
39+
) : SourcedMessageCodec<T> {
40+
override fun encodeToSource(value: T): Source {
4141
return when (serialFormat) {
4242
is StringFormat -> {
4343
val stringValue = serialFormat.encodeToString(serializer, value)
@@ -59,7 +59,7 @@ private class KotlinxSerializationCodec<T>(
5959
}
6060
}
6161

62-
override fun decode(stream: Source): T {
62+
override fun decodeFromSource(stream: Source): T {
6363
return when (serialFormat) {
6464
is StringFormat -> {
6565
serialFormat.decodeFromString(serializer, stream.readString())

grpc/grpc-codec/build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,15 @@ plugins {
77
}
88

99
kotlin {
10+
compilerOptions {
11+
freeCompilerArgs.add("-Xexpect-actual-classes")
12+
}
13+
1014
sourceSets {
1115
commonMain {
1216
dependencies {
1317
api(projects.utils)
18+
api(projects.protobuf.protobufInputStream)
1419
api(libs.kotlinx.io.core)
1520
}
1621
}

grpc/grpc-codec/src/commonMain/kotlin/kotlinx/rpc/grpc/codec/MessageCodec.kt

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ package kotlinx.rpc.grpc.codec
77
import kotlinx.io.Source
88
import kotlinx.rpc.internal.utils.ExperimentalRpcApi
99
import kotlinx.rpc.internal.utils.InternalRpcApi
10+
import kotlinx.rpc.protobuf.input.stream.InputStream
11+
import kotlinx.rpc.protobuf.input.stream.asInputStream
12+
import kotlinx.rpc.protobuf.input.stream.asSource
1013
import kotlin.reflect.KType
1114

1215
@ExperimentalRpcApi
@@ -30,8 +33,22 @@ public operator fun MessageCodecResolver.plus(other: MessageCodecResolver): Mess
3033

3134
@ExperimentalRpcApi
3235
public interface MessageCodec<T> {
33-
public fun encode(value: T): Source
34-
public fun decode(stream: Source): T
36+
public fun encode(value: T): InputStream
37+
public fun decode(stream: InputStream): T
38+
}
39+
40+
@ExperimentalRpcApi
41+
public interface SourcedMessageCodec<T> : MessageCodec<T> {
42+
public fun encodeToSource(value: T): Source
43+
public fun decodeFromSource(stream: Source): T
44+
45+
override fun encode(value: T): InputStream {
46+
return encodeToSource(value).asInputStream()
47+
}
48+
49+
override fun decode(stream: InputStream): T {
50+
return decodeFromSource(stream.asSource())
51+
}
3552
}
3653

3754
@InternalRpcApi

grpc/grpc-core/build.gradle.kts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ kotlin {
4141
implementation(libs.serialization.json)
4242

4343
implementation(projects.grpc.grpcCodecKotlinxSerialization)
44+
implementation(projects.protobuf.protobufCore)
4445
}
4546
}
4647

@@ -76,12 +77,4 @@ kotlin {
7677
}
7778
}
7879

79-
protoSourceSets {
80-
commonTest {
81-
proto {
82-
exclude("exclude/**")
83-
}
84-
}
85-
}
86-
8780
configureLocalProtocGenDevelopmentDependency()

grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/GrpcServer.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package kotlinx.rpc.grpc
66

77
import kotlinx.atomicfu.atomic
88
import kotlinx.coroutines.CoroutineScope
9+
import kotlinx.coroutines.Job
910
import kotlinx.coroutines.SupervisorJob
1011
import kotlinx.coroutines.cancel
1112
import kotlinx.coroutines.flow.Flow
@@ -52,7 +53,7 @@ public class GrpcServer internal constructor(
5253
parentContext: CoroutineContext = EmptyCoroutineContext,
5354
configure: ServerBuilder<*>.() -> Unit,
5455
) : RpcServer, Server {
55-
private val internalContext = SupervisorJob(parentContext.job)
56+
private val internalContext = SupervisorJob(parentContext[Job])
5657
private val internalScope = CoroutineScope(parentContext + internalContext)
5758

5859
private val messageCodecResolver = messageCodecResolver + ThrowingMessageCodecResolver

grpc/grpc-core/src/commonMain/kotlin/kotlinx/rpc/grpc/internal/MethodDescriptor.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,7 @@ package kotlinx.rpc.grpc.internal
66

77
import kotlinx.rpc.grpc.codec.MessageCodec
88
import kotlinx.rpc.internal.utils.InternalRpcApi
9-
10-
@InternalRpcApi
11-
public expect abstract class InputStream
9+
import kotlinx.rpc.protobuf.input.stream.InputStream
1210

1311
@InternalRpcApi
1412
public expect class MethodDescriptor<Request, Response> {

grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/CustomResolverGrpcServiceTest.kt

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ import kotlinx.io.Source
1313
import kotlinx.io.readString
1414
import kotlinx.io.writeString
1515
import kotlinx.rpc.grpc.annotations.Grpc
16-
import kotlinx.rpc.grpc.codec.MessageCodec
1716
import kotlinx.rpc.grpc.codec.MessageCodecResolver
17+
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
1818
import kotlinx.rpc.grpc.codec.WithCodec
1919
import kotlin.test.Test
2020
import kotlin.test.assertContentEquals
2121
import kotlin.test.assertEquals
2222

2323
@WithCodec(Message.Companion::class)
2424
class Message(val value: String) {
25-
companion object : MessageCodec<Message> {
26-
override fun encode(value: Message): Source {
25+
companion object : SourcedMessageCodec<Message> {
26+
override fun encodeToSource(value: Message): Source {
2727
return Buffer().apply { writeString(value.value) }
2828
}
2929

30-
override fun decode(stream: Source): Message {
30+
override fun decodeFromSource(stream: Source): Message {
3131
return Message(stream.readString())
3232
}
3333
}
@@ -135,22 +135,22 @@ class CustomResolverGrpcServiceTest : BaseGrpcServiceTest() {
135135
}
136136
}
137137

138-
val stringCodec = object : MessageCodec<String> {
139-
override fun encode(value: String): Source {
138+
val stringCodec = object : SourcedMessageCodec<String> {
139+
override fun encodeToSource(value: String): Source {
140140
return Buffer().apply { writeString(value) }
141141
}
142142

143-
override fun decode(stream: Source): String {
143+
override fun decodeFromSource(stream: Source): String {
144144
return stream.readString()
145145
}
146146
}
147147

148-
val unitCodec = object : MessageCodec<Unit> {
149-
override fun encode(value: Unit): Source {
148+
val unitCodec = object : SourcedMessageCodec<Unit> {
149+
override fun encodeToSource(value: Unit): Source {
150150
return Buffer()
151151
}
152152

153-
override fun decode(stream: Source) {
153+
override fun decodeFromSource(stream: Source) {
154154
check(stream.exhausted())
155155
}
156156
}

grpc/grpc-core/src/commonTest/kotlin/kotlinx/rpc/grpc/test/RawClientServerTest.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import kotlinx.rpc.grpc.ManagedChannelBuilder
1818
import kotlinx.rpc.grpc.Server
1919
import kotlinx.rpc.grpc.ServerBuilder
2020
import kotlinx.rpc.grpc.buildChannel
21-
import kotlinx.rpc.grpc.codec.MessageCodec
21+
import kotlinx.rpc.grpc.codec.SourcedMessageCodec
2222
import kotlinx.rpc.grpc.internal.GrpcChannel
2323
import kotlinx.rpc.grpc.internal.MethodDescriptor
2424
import kotlinx.rpc.grpc.internal.MethodType
@@ -151,12 +151,12 @@ class RawClientServerTest {
151151
companion object {
152152
private const val SERVICE_NAME = "TestService"
153153

154-
private val simpleCodec = object : MessageCodec<String> {
155-
override fun encode(value: String): Source {
154+
private val simpleCodec = object : SourcedMessageCodec<String> {
155+
override fun encodeToSource(value: String): Source {
156156
return Buffer().apply { writeString(value) }
157157
}
158158

159-
override fun decode(stream: Source): String {
159+
override fun decodeFromSource(stream: Source): String {
160160
return stream.readString()
161161
}
162162
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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.grpc.test.proto
6+
7+
import kotlinx.coroutines.sync.Mutex
8+
import kotlinx.coroutines.sync.withLock
9+
import kotlinx.coroutines.test.runTest
10+
import kotlinx.rpc.RpcServer
11+
import kotlinx.rpc.grpc.GrpcClient
12+
import kotlinx.rpc.grpc.GrpcServer
13+
14+
abstract class GrpcProtoTest {
15+
private val serverMutex = Mutex()
16+
17+
abstract fun RpcServer.registerServices()
18+
19+
protected fun runGrpcTest(test: suspend (GrpcClient) -> Unit, ) = runTest {
20+
serverMutex.withLock {
21+
val grpcClient = GrpcClient("localhost", 8080) {
22+
usePlaintext()
23+
}
24+
25+
val grpcServer = GrpcServer(8080, builder = {
26+
registerServices()
27+
})
28+
29+
grpcServer.start()
30+
test(grpcClient)
31+
grpcServer.shutdown()
32+
grpcServer.awaitTermination()
33+
grpcClient.shutdown()
34+
grpcClient.awaitTermination()
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)