Skip to content

Commit 775e741

Browse files
committed
pb: Documentation update
1 parent e5fb28b commit 775e741

File tree

3 files changed

+177
-3
lines changed

3 files changed

+177
-3
lines changed
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
* Copyright 2023-2026 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.integration
6+
7+
import kotlinx.rpc.RpcServer
8+
import kotlinx.rpc.grpc.annotations.Grpc
9+
import kotlinx.rpc.grpc.codec.codec
10+
import kotlinx.rpc.grpc.test.AllPrimitives
11+
import kotlinx.rpc.grpc.test.Enum
12+
import kotlinx.rpc.grpc.test.UnknownFieldsAll
13+
import kotlinx.rpc.grpc.test.UnknownFieldsSubset
14+
import kotlinx.rpc.grpc.test.asInternal
15+
import kotlinx.rpc.grpc.test.invoke
16+
import kotlinx.rpc.grpc.test.presence
17+
import kotlinx.rpc.protobuf.ProtobufConfig
18+
import kotlinx.rpc.registerService
19+
import kotlinx.rpc.withService
20+
import kotlin.test.Test
21+
import kotlin.test.assertEquals
22+
import kotlin.test.assertFalse
23+
import kotlin.test.assertNull
24+
import kotlin.test.assertTrue
25+
26+
27+
@Grpc(protoServiceName = "Service")
28+
private interface ClientTestService {
29+
suspend fun serverTest(message: UnknownFieldsAll): UnknownFieldsAll
30+
suspend fun clientTest(message: UnknownFieldsAll): UnknownFieldsSubset
31+
}
32+
33+
@Grpc(protoServiceName = "Service")
34+
private interface ServerTestService {
35+
suspend fun serverTest(message: UnknownFieldsSubset): UnknownFieldsSubset
36+
suspend fun clientTest(message: UnknownFieldsAll): UnknownFieldsAll
37+
}
38+
39+
private object ServerServiceImpl : ServerTestService {
40+
override suspend fun serverTest(message: UnknownFieldsSubset): UnknownFieldsSubset = message
41+
override suspend fun clientTest(message: UnknownFieldsAll): UnknownFieldsAll = message
42+
}
43+
44+
class GrpcCodecConfigTest : GrpcTestBase() {
45+
46+
override fun RpcServer.registerServices() {
47+
registerService<ServerTestService> { ServerServiceImpl }
48+
}
49+
50+
private val unknownFieldsAllMessage = UnknownFieldsAll {
51+
field1 = 123
52+
intMissing = 456
53+
allPrimitivesMissing = AllPrimitives {
54+
int32 = 7
55+
}
56+
enumMissing = Enum.ONE
57+
testOneof = UnknownFieldsAll.TestOneof.OneofString("oneof value")
58+
}
59+
60+
61+
@Test
62+
fun `test protobuf discardUnknownFields codec config in server config`() = runGrpcTest(
63+
serverConfiguration = { codecConfig = ProtobufConfig(discardUnknownFields = true) }
64+
) { client ->
65+
val service = client.withService<ClientTestService>()
66+
val message = unknownFieldsAllMessage
67+
val response = service.serverTest(message)
68+
69+
// the server should have discarded unknown fields
70+
response.run {
71+
assertEquals(message.field1, field1)
72+
assertFalse(response.presence.hasIntMissing)
73+
assertFalse(response.presence.hasAllPrimitivesMissing)
74+
assertFalse(response.presence.hasEnumMissing)
75+
assertNull(response.testOneof)
76+
}
77+
}
78+
79+
@Test
80+
fun `test unknown fields presents by default - server`() = runGrpcTest { client ->
81+
val service = client.withService<ClientTestService>()
82+
val message = unknownFieldsAllMessage
83+
val response = service.serverTest(message)
84+
85+
// the server should have preserved unknown fields
86+
assertEquals(message, response)
87+
}
88+
89+
@Test
90+
fun `test protobuf discardUnknownFields codec config in client config`() = runGrpcTest(
91+
clientConfiguration = { codecConfig = ProtobufConfig(discardUnknownFields = true) }
92+
) { client ->
93+
val service = client.withService<ClientTestService>()
94+
val message = unknownFieldsAllMessage
95+
val response = service.clientTest(message)
96+
97+
// the client should have discarded unknown fields
98+
assertEquals(0, response.asInternal()._unknownFields.size)
99+
}
100+
101+
102+
@Test
103+
fun `test unknown fields presents by default - client`() = runGrpcTest { client ->
104+
val service = client.withService<ClientTestService>()
105+
val message = unknownFieldsAllMessage
106+
val response = service.clientTest(message)
107+
108+
// the server should have preserved unknown fields
109+
assertTrue(response.asInternal()._unknownFields.size > 0)
110+
111+
// encode and decode as UnknownFieldsAll
112+
val codec = codec<UnknownFieldsAll>()
113+
val decoded = codec.decode(codec.encode(message))
114+
// should have preserved all fields
115+
assertEquals(message, decoded)
116+
}
117+
118+
119+
}

protobuf/protobuf-core/src/commonMain/kotlin/kotlinx/rpc/protobuf/ProtobufConfig.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ package kotlinx.rpc.protobuf
77
import kotlinx.rpc.grpc.codec.CodecConfig
88

99
/**
10-
* Configuration options for Protocol Buffers message encoding and decoding.
10+
* Configuration options for Protobuf message encoding and decoding.
1111
*
1212
* This class implements [CodecConfig] to provide Protobuf-specific configuration that controls
13-
* how messages are serialized and deserialized when using Protocol Buffers codecs generated from
14-
* `.proto` files using the `kotlinx-rpc`.
13+
* how messages are serialized and deserialized when using Protobuf codecs generated from
14+
* `.proto` files using `kotlinx-rpc`.
1515
*
1616
* Example:
1717
* ```kotlin
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
syntax = "proto3";
2+
3+
import "all_primitives_grpc.proto";
4+
import "enum_grpc.proto";
5+
import "repeated_grpc.proto";
6+
import "test_map_grpc.proto";
7+
8+
package kotlinx.rpc.grpc.test;
9+
10+
// Message with all types of fields that might become unknown
11+
message UnknownFieldsAll {
12+
optional int32 field1 = 1;
13+
// All primitive types
14+
optional int32 intMissing = 2;
15+
optional int64 int64Missing = 3;
16+
optional uint32 uint32Missing = 4;
17+
optional uint64 uint64Missing = 5;
18+
optional sint32 sint32Missing = 6;
19+
optional sint64 sint64Missing = 7;
20+
optional fixed32 fixed32Missing = 8;
21+
optional fixed64 fixed64Missing = 9;
22+
optional sfixed32 sfixed32Missing = 10;
23+
optional sfixed64 sfixed64Missing = 11;
24+
optional bool boolMissing = 12;
25+
optional string stringMissing = 13;
26+
optional bytes bytesMissing = 14;
27+
optional float floatMissing = 15;
28+
optional double doubleMissing = 16;
29+
optional AllPrimitives allPrimitivesMissing = 17;
30+
optional TestMap mapMessageMissing = 20;
31+
// Enum from existing proto
32+
optional Enum enumMissing = 21;
33+
// Repeated fields
34+
repeated int32 repeatedIntMissing = 22;
35+
repeated string repeatedStringMissing = 23;
36+
repeated AllPrimitives repeatedMessageMissing = 24;
37+
repeated fixed32 repeatedFixed32Missing = 25 [packed = true];
38+
repeated Enum repeatedEnumMissing = 26;
39+
// Map fields
40+
map<string, int32> mapStringIntMissing = 27;
41+
map<int32, string> mapIntStringMissing = 28;
42+
map<string, AllPrimitives> mapStringMessageMissing = 29;
43+
// Oneof field
44+
oneof test_oneof {
45+
int32 oneofInt = 30;
46+
string oneofString = 31;
47+
AllPrimitives oneofMessage = 32;
48+
Enum oneofEnum = 33;
49+
}
50+
}
51+
52+
// Message with only a subset of fields - most will be unknown when deserializing UnknownFieldsAll
53+
message UnknownFieldsSubset {
54+
optional int32 field1 = 1;
55+
}

0 commit comments

Comments
 (0)