Tidy up dependencies in sample
This commit is contained in:
@@ -37,11 +37,9 @@ dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-actuator'
|
||||
implementation 'io.grpc:grpc-services'
|
||||
implementation "io.grpc:grpc-kotlin-stub:${kotlinStubVersion}"
|
||||
implementation 'com.google.protobuf:protobuf-kotlin'
|
||||
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.10.2'
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.grpc:spring-grpc-test'
|
||||
|
||||
@@ -51,24 +51,15 @@
|
||||
<groupId>org.springframework.grpc</groupId>
|
||||
<artifactId>spring-grpc-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-coroutines-core</artifactId>
|
||||
<version>1.10.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-kotlin-stub</artifactId>
|
||||
<version>${grpc.kotlin.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.protobuf</groupId>
|
||||
<artifactId>protobuf-kotlin</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.grpc</groupId>
|
||||
<artifactId>grpc-services</artifactId>
|
||||
@@ -90,24 +81,6 @@
|
||||
<artifactId>spring-grpc-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>24.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>24.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains</groupId>
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>24.0.1</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
package org.springframework.grpc.sample
|
||||
|
||||
import io.grpc.stub.AbstractStub
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.context.TestConfiguration
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.grpc.client.FutureStubFactory
|
||||
import org.springframework.grpc.client.ImportGrpcClients
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc.SimpleBlockingStub
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc.SimpleFutureStub
|
||||
import org.springframework.grpc.test.AutoConfigureInProcessTransport
|
||||
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureInProcessTransport
|
||||
class NoAutowiredClients {
|
||||
|
||||
@Autowired
|
||||
private lateinit var context: ApplicationContext
|
||||
|
||||
@Test
|
||||
fun noStubIsCreated() {
|
||||
assertThat(context.containsBeanDefinition("simpleBlockingStub")).isFalse()
|
||||
assertThat(context.containsBeanDefinition("simpleStub")).isFalse()
|
||||
assertThat(context.containsBeanDefinition("simpleFutureStub")).isFalse()
|
||||
assertThat(context.getBeanNamesForType(AbstractStub::class.java))
|
||||
.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootTest(properties = ["spring.grpc.client.default-channel.address=0.0.0.0:9090"])
|
||||
@AutoConfigureInProcessTransport
|
||||
class DefaultAutowiredClients {
|
||||
@Autowired
|
||||
private lateinit var context: ApplicationContext
|
||||
|
||||
@Test
|
||||
fun onlyDefaultStubIsCreated() {
|
||||
Assertions.assertThat(context.containsBeanDefinition("simpleBlockingStub")).isTrue()
|
||||
assertThat(
|
||||
context.getBean(
|
||||
SimpleBlockingStub::class.java
|
||||
)
|
||||
).isNotNull()
|
||||
assertThat(context.containsBeanDefinition("simpleStub")).isFalse()
|
||||
assertThat(context.containsBeanDefinition("simpleFutureStub")).isFalse()
|
||||
assertThat(context.getBeanNamesForType(AbstractStub::class.java))
|
||||
.hasSize(1)
|
||||
}
|
||||
}
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.client.default-channel.address=0.0.0.0:9090"]
|
||||
)
|
||||
@AutoConfigureInProcessTransport
|
||||
class SpecificAutowiredClients {
|
||||
@Autowired
|
||||
private lateinit var context: ApplicationContext
|
||||
|
||||
@Test
|
||||
fun stubOfCorrectTypeIsCreated() {
|
||||
assertThat(context.containsBeanDefinition("simpleFutureStub")).isTrue()
|
||||
assertThat(
|
||||
context.getBean(
|
||||
SimpleFutureStub::class.java
|
||||
)
|
||||
).isNotNull()
|
||||
assertThat(context.containsBeanDefinition("simpleStub")).isFalse()
|
||||
assertThat(context.containsBeanDefinition("simpleBlockingStub")).isFalse()
|
||||
assertThat(context.getBeanNamesForType(AbstractStub::class.java))
|
||||
.hasSize(1)
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
@ImportGrpcClients(basePackageClasses = [SimpleGrpc::class], factory = FutureStubFactory::class)
|
||||
internal open class TestConfig
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.grpc.sample
|
||||
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.grpc.health.v1.HealthCheckRequest
|
||||
import io.grpc.health.v1.HealthCheckResponse.ServingStatus
|
||||
import io.grpc.health.v1.HealthGrpc
|
||||
import io.grpc.health.v1.HealthGrpc.HealthBlockingStub
|
||||
import io.grpc.protobuf.services.HealthStatusManager
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.assertj.core.api.ThrowableAssert
|
||||
import org.awaitility.Awaitility
|
||||
import org.awaitility.core.ThrowingRunnable
|
||||
import org.junit.jupiter.api.Nested
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator
|
||||
import org.springframework.boot.actuate.health.Health
|
||||
import org.springframework.boot.actuate.health.HealthIndicator
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.context.TestConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.grpc.client.GrpcChannelFactory
|
||||
import org.springframework.grpc.sample.proto.HelloRequest
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc.SimpleBlockingStub
|
||||
import org.springframework.grpc.test.AutoConfigureInProcessTransport
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import java.time.Duration
|
||||
|
||||
/**
|
||||
* Integration tests for gRPC server health feature.
|
||||
*/
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.server.port=0", "spring.grpc.client.channels.health-test.address=static://0.0.0.0:\${local.grpc.port}", "spring.grpc.client.channels.health-test.health.enabled=true", "spring.grpc.client.channels.health-test.health.service-name=my-service"]
|
||||
)
|
||||
@DirtiesContext
|
||||
class WithClientHealthEnabled {
|
||||
@Test
|
||||
fun loadBalancerRespectsServerHealth(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@Autowired healthStatusManager: HealthStatusManager
|
||||
) {
|
||||
val channel = channels.createChannel("health-test")
|
||||
val client = SimpleGrpc.newBlockingStub(channel)
|
||||
|
||||
// put the service up (SERVING) and give load balancer time to update
|
||||
updateHealthStatusAndWait("my-service", ServingStatus.SERVING, healthStatusManager)
|
||||
|
||||
// initially the status should be SERVING
|
||||
assertThatResponseIsServedToChannel(client)
|
||||
|
||||
// put the service down (NOT_SERVING) and give load balancer time to update
|
||||
updateHealthStatusAndWait("my-service", ServingStatus.NOT_SERVING, healthStatusManager)
|
||||
|
||||
// now the request should fail
|
||||
assertThatResponseIsNotServedToChannel(client)
|
||||
|
||||
// put the service up (SERVING) and give load balancer time to update
|
||||
updateHealthStatusAndWait("my-service", ServingStatus.SERVING, healthStatusManager)
|
||||
|
||||
// now the request should pass
|
||||
assertThatResponseIsServedToChannel(client)
|
||||
}
|
||||
|
||||
private fun updateHealthStatusAndWait(
|
||||
serviceName: String?, healthStatus: ServingStatus,
|
||||
healthStatusManager: HealthStatusManager
|
||||
) {
|
||||
healthStatusManager.setStatus(serviceName, healthStatus)
|
||||
try {
|
||||
Thread.sleep(2000L)
|
||||
} catch (e: InterruptedException) {
|
||||
throw RuntimeException(e)
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertThatResponseIsServedToChannel(client: SimpleBlockingStub) {
|
||||
val response = client.sayHello(HelloRequest.newBuilder().setName("Alien").build())
|
||||
Assertions.assertThat(response.getMessage()).isEqualTo("Hello ==> Alien")
|
||||
}
|
||||
|
||||
private fun assertThatResponseIsNotServedToChannel(client: SimpleBlockingStub) {
|
||||
Assertions.assertThatExceptionOfType<StatusRuntimeException?>(StatusRuntimeException::class.java)
|
||||
.isThrownBy(ThrowableAssert.ThrowingCallable {
|
||||
client.sayHello(
|
||||
HelloRequest.newBuilder().setName("Alien").build()
|
||||
)
|
||||
})
|
||||
.withMessageContaining("UNAVAILABLE: Health-check service responded NOT_SERVING for 'my-service'")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.server.health.actuator.health-indicator-paths=custom", "spring.grpc.server.health.actuator.update-initial-delay=3s", "spring.grpc.server.health.actuator.update-rate=3s", "management.health.defaults.enabled=true"]
|
||||
)
|
||||
@AutoConfigureInProcessTransport
|
||||
@DirtiesContext
|
||||
class WithActuatorHealthAdapter {
|
||||
@Test
|
||||
fun healthIndicatorsAdaptedToGrpcHealthStatus(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@Autowired customHealthIndicator: CustomHealthIndicator
|
||||
) {
|
||||
val channel = channels.createChannel("0.0.0.0:0")
|
||||
val healthStub = HealthGrpc.newBlockingStub(channel)
|
||||
val serviceName = "custom"
|
||||
|
||||
// initially the status should be SERVING
|
||||
assertThatGrpcHealthStatusIs(healthStub, serviceName, ServingStatus.SERVING, Duration.ofSeconds(4))
|
||||
|
||||
// put the service down and the status should then be NOT_SERVING
|
||||
customHealthIndicator.SERVICE_IS_UP = false
|
||||
assertThatGrpcHealthStatusIs(healthStub, serviceName, ServingStatus.NOT_SERVING, Duration.ofSeconds(4))
|
||||
|
||||
// put the service up and the status should be SERVING
|
||||
customHealthIndicator.SERVICE_IS_UP = true
|
||||
assertThatGrpcHealthStatusIs(healthStub, serviceName, ServingStatus.SERVING, Duration.ofSeconds(4))
|
||||
}
|
||||
|
||||
private fun assertThatGrpcHealthStatusIs(
|
||||
healthBlockingStub: HealthBlockingStub, service: String,
|
||||
expectedStatus: ServingStatus?, maxWaitTime: Duration?
|
||||
) {
|
||||
Awaitility.await().atMost(maxWaitTime).ignoreException(StatusRuntimeException::class.java).untilAsserted {
|
||||
val healthRequest = HealthCheckRequest.newBuilder().setService(service).build()
|
||||
val healthResponse = healthBlockingStub.check(healthRequest)
|
||||
Assertions.assertThat(healthResponse.getStatus()).isEqualTo(expectedStatus)
|
||||
// verify the overall status as well
|
||||
val overallHealthRequest = HealthCheckRequest.newBuilder().setService("").build()
|
||||
val overallHealthResponse = healthBlockingStub.check(overallHealthRequest)
|
||||
Assertions.assertThat(overallHealthResponse.getStatus()).isEqualTo(expectedStatus)
|
||||
}
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
internal open class MyHealthIndicatorsConfig {
|
||||
@ConditionalOnEnabledHealthIndicator("custom")
|
||||
@Bean
|
||||
open fun customHealthIndicator(): CustomHealthIndicator {
|
||||
return CustomHealthIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
class CustomHealthIndicator : HealthIndicator {
|
||||
override fun health(): Health? {
|
||||
return if (SERVICE_IS_UP) Health.up().build() else Health.down().build()
|
||||
}
|
||||
|
||||
var SERVICE_IS_UP: Boolean = true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,332 +0,0 @@
|
||||
/*
|
||||
* Copyright 2024-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.grpc.sample
|
||||
|
||||
import io.grpc.ForwardingServerCallListener
|
||||
import io.grpc.ManagedChannel
|
||||
import io.grpc.Metadata
|
||||
import io.grpc.ServerCall
|
||||
import io.grpc.ServerCallHandler
|
||||
import io.grpc.ServerInterceptor
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.grpc.netty.NettyChannelBuilder
|
||||
import org.assertj.core.api.Assertions
|
||||
import org.junit.Assert
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.context.TestConfiguration
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.grpc.client.ChannelBuilderOptions
|
||||
import org.springframework.grpc.client.GrpcChannelBuilderCustomizer
|
||||
import org.springframework.grpc.client.GrpcChannelFactory
|
||||
import org.springframework.grpc.sample.proto.HelloRequest
|
||||
import org.springframework.grpc.sample.proto.SimpleGrpc
|
||||
import org.springframework.grpc.server.GlobalServerInterceptor
|
||||
import org.springframework.grpc.test.AutoConfigureInProcessTransport
|
||||
import org.springframework.grpc.test.LocalGrpcPort
|
||||
import org.springframework.test.annotation.DirtiesContext
|
||||
import org.springframework.test.context.ActiveProfiles
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
/**
|
||||
* More detailed integration tests for [gRPC server factories][GrpcServerFactory] and
|
||||
* various [GrpcServerProperties].
|
||||
*/
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureInProcessTransport
|
||||
class ServerWithInProcessChannel {
|
||||
@Test
|
||||
fun servesResponseToClient(@Autowired channels: GrpcChannelFactory) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("0.0.0.0:0"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureInProcessTransport
|
||||
class ServerWithException {
|
||||
|
||||
@Test
|
||||
fun specificErrorResponse(@Autowired channels: GrpcChannelFactory) {
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat(
|
||||
Assert.assertThrows(StatusRuntimeException::class.java) {
|
||||
client.sayHello(
|
||||
HelloRequest.newBuilder().setName("error").build()
|
||||
)
|
||||
}
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.INVALID_ARGUMENT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun defaultErrorResponseIsUnknown(@Autowired channels: GrpcChannelFactory) {
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat(
|
||||
Assert.assertThrows(
|
||||
StatusRuntimeException::class.java
|
||||
) { client.sayHello(HelloRequest.newBuilder().setName("internal").build()) }
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureInProcessTransport
|
||||
class ServerWithExceptionInInterceptorCall {
|
||||
@Test
|
||||
fun specificErrorResponse(@Autowired channels: GrpcChannelFactory) {
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat(
|
||||
Assert.assertThrows(
|
||||
StatusRuntimeException::class.java
|
||||
) { client.sayHello(HelloRequest.newBuilder().setName("error").build()) }
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.INVALID_ARGUMENT)
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
internal open class TestConfig {
|
||||
@Bean
|
||||
@GlobalServerInterceptor
|
||||
open fun exceptionInterceptor(): ServerInterceptor {
|
||||
return CustomInterceptor()
|
||||
}
|
||||
|
||||
internal class CustomInterceptor : ServerInterceptor {
|
||||
override fun <ReqT, RespT> interceptCall(
|
||||
call: ServerCall<ReqT?, RespT?>?, headers: Metadata?,
|
||||
next: ServerCallHandler<ReqT?, RespT?>?
|
||||
): ServerCall.Listener<ReqT?>? {
|
||||
throw IllegalArgumentException("test")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest
|
||||
@AutoConfigureInProcessTransport
|
||||
class ServerWithExceptionInInterceptorListener {
|
||||
@Test
|
||||
fun specificErrorResponse(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@Autowired testConfig: TestConfig
|
||||
) {
|
||||
testConfig.reset()
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat(
|
||||
Assert.assertThrows(
|
||||
StatusRuntimeException::class.java
|
||||
) { client.sayHello(HelloRequest.newBuilder().setName("foo").build()) }
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.INVALID_ARGUMENT)
|
||||
Assertions.assertThat(TestConfig.readyCount.get()).isEqualTo(1)
|
||||
Assertions.assertThat(TestConfig.callCount.get()).isEqualTo(0)
|
||||
Assertions.assertThat(TestConfig.messageCount.get()).isEqualTo(0)
|
||||
}
|
||||
|
||||
@TestConfiguration
|
||||
open class TestConfig {
|
||||
companion object {
|
||||
var callCount: AtomicInteger = AtomicInteger()
|
||||
var messageCount: AtomicInteger = AtomicInteger()
|
||||
var readyCount: AtomicInteger = AtomicInteger()
|
||||
}
|
||||
|
||||
fun reset() {
|
||||
callCount.set(0)
|
||||
messageCount.set(0)
|
||||
readyCount.set(0)
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@GlobalServerInterceptor
|
||||
open fun exceptionInterceptor(): ServerInterceptor {
|
||||
return CustomInterceptor()
|
||||
}
|
||||
|
||||
internal class CustomInterceptor : ServerInterceptor {
|
||||
override fun <ReqT, RespT> interceptCall(
|
||||
call: ServerCall<ReqT?, RespT?>?, headers: Metadata?,
|
||||
next: ServerCallHandler<ReqT?, RespT?>
|
||||
): ServerCall.Listener<ReqT?> {
|
||||
return CustomListener(next.startCall(call, headers))
|
||||
}
|
||||
}
|
||||
|
||||
internal class CustomListener<ReqT>(private val delegate: ServerCall.Listener<ReqT?>?) :
|
||||
ForwardingServerCallListener<ReqT?>() {
|
||||
override fun onReady() {
|
||||
readyCount.incrementAndGet()
|
||||
throw IllegalArgumentException("test")
|
||||
}
|
||||
|
||||
override fun onHalfClose() {
|
||||
callCount.incrementAndGet()
|
||||
super.onHalfClose()
|
||||
}
|
||||
|
||||
override fun onMessage(message: ReqT?) {
|
||||
messageCount.incrementAndGet()
|
||||
super.onMessage(message)
|
||||
}
|
||||
|
||||
override fun delegate(): ServerCall.Listener<ReqT?>? {
|
||||
return this.delegate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest("spring.grpc.server.exception-handler.enabled=false")
|
||||
@AutoConfigureInProcessTransport
|
||||
class ServerWithUnhandledException {
|
||||
@Test
|
||||
fun specificErrorResponse(@Autowired channels: GrpcChannelFactory) {
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat<Status.Code?>(
|
||||
Assert.assertThrows(StatusRuntimeException::class.java) {
|
||||
client.sayHello(
|
||||
HelloRequest.newBuilder().setName("error").build()
|
||||
)
|
||||
}
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.UNKNOWN)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun defaultErrorResponseIsUnknown(@Autowired channels: GrpcChannelFactory) {
|
||||
val client = SimpleGrpc.newBlockingStub(channels.createChannel("0.0.0.0:0"))
|
||||
Assertions.assertThat(
|
||||
Assert.assertThrows(
|
||||
StatusRuntimeException::class.java
|
||||
) { client.sayHello(HelloRequest.newBuilder().setName("internal").build()) }
|
||||
.status
|
||||
.code
|
||||
).isEqualTo(Status.Code.UNKNOWN)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(properties = ["spring.grpc.server.host=0.0.0.0", "spring.grpc.server.port=0"])
|
||||
class ServerWithAnyIPv4AddressAndRandomPort {
|
||||
@Test
|
||||
fun servesResponseToClientWithAnyIPv4AddressAndRandomPort(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@LocalGrpcPort port: Int
|
||||
) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("0.0.0.0:" + port))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(properties = ["spring.grpc.server.host=::", "spring.grpc.server.port=0"])
|
||||
class ServerWithAnyIPv6AddressAndRandomPort {
|
||||
@Test
|
||||
fun servesResponseToClientWithAnyIPv4AddressAndRandomPort(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@LocalGrpcPort port: Int
|
||||
) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("0.0.0.0:" + port))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(properties = ["spring.grpc.server.host=127.0.0.1", "spring.grpc.server.port=0"])
|
||||
class ServerWithLocalhostAndRandomPort {
|
||||
@Test
|
||||
fun servesResponseToClientWithLocalhostAndRandomPort(
|
||||
@Autowired channels: GrpcChannelFactory,
|
||||
@LocalGrpcPort port: Int
|
||||
) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("127.0.0.1:" + port))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.server.port=0", "spring.grpc.client.channels.test-channel.address=static://0.0.0.0:\${local.grpc.port}"]
|
||||
)
|
||||
@DirtiesContext
|
||||
class ServerConfiguredWithStaticClientChannel {
|
||||
@Test
|
||||
fun servesResponseToClientWithConfiguredChannel(@Autowired channels: GrpcChannelFactory) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("test-channel"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(properties = ["spring.grpc.server.address=unix:unix-test-channel"])
|
||||
@EnabledOnOs(OS.LINUX)
|
||||
class ServerWithUnixDomain {
|
||||
@Test
|
||||
fun clientChannelWithUnixDomain(@Autowired channels: GrpcChannelFactory) {
|
||||
assertThatResponseIsServedToChannel(
|
||||
channels.createChannel(
|
||||
"unix:unix-test-channel",
|
||||
ChannelBuilderOptions.defaults()
|
||||
.withCustomizer<NettyChannelBuilder?>(GrpcChannelBuilderCustomizer { `__`: String?, b: NettyChannelBuilder? -> b!!.usePlaintext() })
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.server.port=0", "spring.grpc.client.channels.test-channel.address=static://0.0.0.0:\${local.grpc.port}", "spring.grpc.client.channels.test-channel.negotiation-type=TLS", "spring.grpc.client.channels.test-channel.secure=false"]
|
||||
)
|
||||
@ActiveProfiles("ssl")
|
||||
@DirtiesContext
|
||||
class ServerWithSsl {
|
||||
@Test
|
||||
fun clientChannelWithSsl(@Autowired channels: GrpcChannelFactory) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("test-channel"))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@SpringBootTest(
|
||||
properties = ["spring.grpc.server.port=0", "spring.grpc.server.ssl.client-auth=REQUIRE", "spring.grpc.server.ssl.secure=false", "spring.grpc.client.channels.test-channel.address=static://0.0.0.0:\${local.grpc.port}", "spring.grpc.client.channels.test-channel.ssl.bundle=ssltest", "spring.grpc.client.channels.test-channel.negotiation-type=TLS", "spring.grpc.client.channels.test-channel.secure=false"]
|
||||
)
|
||||
@ActiveProfiles("ssl")
|
||||
@DirtiesContext
|
||||
class ServerWithClientAuth {
|
||||
@Test
|
||||
fun clientChannelWithSsl(@Autowired channels: GrpcChannelFactory) {
|
||||
assertThatResponseIsServedToChannel(channels.createChannel("test-channel"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun assertThatResponseIsServedToChannel(clientChannel: ManagedChannel?) {
|
||||
val client = SimpleGrpc.newBlockingStub(clientChannel)
|
||||
val response = client.sayHello(HelloRequest.newBuilder().setName("Alien").build())
|
||||
Assertions.assertThat(response.getMessage()).isEqualTo("Hello ==> Alien")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user