Backoff from exposing gRPC server port if gRPC is not available

This moves the feature from a unconditional application listener that
can load gRPC types to an auto-configuration that backs off if the
necessary classes are not present.

Also updated the smoke tests to actually use the feature.

Closes gh-50825
This commit is contained in:
Stéphane Nicoll
2026-08-07 11:13:32 +02:00
parent 55bb4eb0c6
commit bf461b085d
8 changed files with 64 additions and 94 deletions
@@ -28,7 +28,7 @@ dependencies {
}
implementation("io.grpc:grpc-netty-shaded")
dockerTestImplementation(project(":starter:spring-boot-starter-test"))
dockerTestImplementation(project(":starter:spring-boot-starter-grpc-server-test"))
dockerTestImplementation("org.testcontainers:testcontainers-junit-jupiter")
}
@@ -21,13 +21,9 @@ import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import smoketest.grpcservernettyshaded.SampleGrpcServerNettyShadedApplicationTests.GrpcServerStartedEventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Import;
import org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;
import static org.assertj.core.api.Assertions.assertThat;
@@ -38,18 +34,16 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@SpringBootTest(properties = "spring.grpc.server.port=0")
@Testcontainers(disabledWithoutDocker = true)
@Import(GrpcServerStartedEventListener.class)
class SampleGrpcServerNettyShadedApplicationTests {
@Autowired
private GrpcServerStartedEventListener startedEventListener;
@Value("${local.grpc.server.port}")
private int port;
@Test
@SuppressWarnings("resource")
void test() {
int port = this.startedEventListener.getPort();
String address = "host.testcontainers.internal:" + port;
org.testcontainers.Testcontainers.exposeHostPorts(port);
String address = "host.testcontainers.internal:" + this.port;
org.testcontainers.Testcontainers.exposeHostPorts(this.port);
try (GenericContainer<?> container = new GenericContainer<>(
DockerImageName.parse("fullstorydev/grpcurl:v1.9.3"))
.withCommand("-d", "{\"name\": \"spring\"}", "--plaintext", address, "HelloWorld/SayHello")
@@ -60,19 +54,4 @@ class SampleGrpcServerNettyShadedApplicationTests {
}
static class GrpcServerStartedEventListener implements ApplicationListener<GrpcServerStartedEvent> {
private int port;
@Override
public void onApplicationEvent(GrpcServerStartedEvent event) {
this.port = event.getPort();
}
int getPort() {
return this.port;
}
}
}
@@ -25,7 +25,7 @@ description = "Spring Boot gRPC server smoke test"
dependencies {
implementation(project(":starter:spring-boot-starter-grpc-server"))
dockerTestImplementation(project(":starter:spring-boot-starter-test"))
dockerTestImplementation(project(":starter:spring-boot-starter-grpc-server-test"))
dockerTestImplementation("org.testcontainers:testcontainers-junit-jupiter")
}
@@ -21,35 +21,30 @@ import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.startupcheck.IndefiniteWaitOneShotStartupCheckStrategy;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
import smoketest.grpcserver.SampleGrpcServerApplicationTests.GrpcServerStartedEventListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Import;
import org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Integration tests for the default Spring gRPC netty server.
* Integration tests for the default Spring gRPC Netty server.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
@SpringBootTest(properties = "spring.grpc.server.port=0")
@Testcontainers(disabledWithoutDocker = true)
@Import(GrpcServerStartedEventListener.class)
class SampleGrpcServerApplicationTests {
@Autowired
private GrpcServerStartedEventListener startedEventListener;
@Value("${local.grpc.server.port}")
private int port;
@Test
@SuppressWarnings("resource")
void test() {
int port = this.startedEventListener.getPort();
String address = "host.testcontainers.internal:" + port;
org.testcontainers.Testcontainers.exposeHostPorts(port);
String address = "host.testcontainers.internal:" + this.port;
org.testcontainers.Testcontainers.exposeHostPorts(this.port);
try (GenericContainer<?> container = new GenericContainer<>(
DockerImageName.parse("fullstorydev/grpcurl:v1.9.3"))
.withNetworkAliases("")
@@ -61,19 +56,4 @@ class SampleGrpcServerApplicationTests {
}
static class GrpcServerStartedEventListener implements ApplicationListener<GrpcServerStartedEvent> {
private int port;
@Override
public void onApplicationEvent(GrpcServerStartedEvent event) {
this.port = event.getPort();
}
int getPort() {
return this.port;
}
}
}