mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-17 12:09:16 +00:00
Merge branch '4.1.x'
Closes gh-51291
This commit is contained in:
+25
-15
@@ -21,11 +21,14 @@ import java.util.Map;
|
||||
|
||||
import io.grpc.Server;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.env.ConfigTreePropertySource.Value;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
@@ -36,34 +39,41 @@ import org.springframework.grpc.server.InProcessGrpcServerFactory;
|
||||
import org.springframework.grpc.server.lifecycle.GrpcServerStartedEvent;
|
||||
|
||||
/**
|
||||
* {@link ApplicationContextInitializer} that sets {@link Environment} properties for the
|
||||
* ports that {@link Server gRPC servers} are actually listening on. The property
|
||||
* {@literal "local.grpc.server.port"} can be injected directly into tests using
|
||||
* {@link Value @Value} or obtained through the {@link Environment}.
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for an {@link ApplicationListener}
|
||||
* that sets {@link Environment} properties for the port that a {@link Server gRPC server}
|
||||
* is actually listening on. The property {@value PROPERTY_NAME} can be injected directly
|
||||
* into tests using {@link Value @Value} or obtained through the {@link Environment}.
|
||||
* <p>
|
||||
* Properties are automatically propagated up to any parent context.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Chris Bono
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
* @since 4.1.1
|
||||
*/
|
||||
class GrpcPortInfoApplicationContextInitializer
|
||||
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
|
||||
@AutoConfiguration(beforeName = "org.springframework.boot.grpc.server.autoconfigure.GrpcServerAutoConfiguration")
|
||||
@ConditionalOnClass(GrpcServerStartedEvent.class)
|
||||
public final class GrpcServerPortInfoAutoConfiguration {
|
||||
|
||||
@Override
|
||||
public void initialize(ConfigurableApplicationContext applicationContext) {
|
||||
applicationContext.addApplicationListener(new Listener(applicationContext));
|
||||
/**
|
||||
* Property that contains the port that a {@link Server gRPC server} is actually
|
||||
* listening on.
|
||||
*/
|
||||
public static final String PROPERTY_NAME = "local.grpc.server.port";
|
||||
|
||||
@Bean
|
||||
GrpcPortInfoApplicationListener grpcPortInfoApplicationListener(ConfigurableApplicationContext applicationContext) {
|
||||
return new GrpcPortInfoApplicationListener(applicationContext);
|
||||
}
|
||||
|
||||
private static class Listener implements ApplicationListener<GrpcServerStartedEvent> {
|
||||
|
||||
private static final String PROPERTY_NAME = "local.grpc.server.port";
|
||||
static class GrpcPortInfoApplicationListener implements ApplicationListener<GrpcServerStartedEvent> {
|
||||
|
||||
private static final String PROPERTY_SOURCE_NAME = "server.ports";
|
||||
|
||||
private final ConfigurableApplicationContext applicationContext;
|
||||
|
||||
Listener(ConfigurableApplicationContext applicationContext) {
|
||||
GrpcPortInfoApplicationListener(ConfigurableApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Application Context Initializers
|
||||
org.springframework.context.ApplicationContextInitializer=\
|
||||
org.springframework.boot.grpc.test.autoconfigure.GrpcPortInfoApplicationContextInitializer
|
||||
+1
@@ -0,0 +1 @@
|
||||
org.springframework.boot.grpc.test.autoconfigure.GrpcServerPortInfoAutoConfiguration
|
||||
+24
-21
@@ -20,10 +20,10 @@ import io.grpc.Server;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.grpc.test.autoconfigure.GrpcServerPortInfoAutoConfiguration.GrpcPortInfoApplicationListener;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.grpc.server.GrpcServerFactory;
|
||||
import org.springframework.grpc.server.InProcessGrpcServerFactory;
|
||||
import org.springframework.grpc.server.NettyGrpcServerFactory;
|
||||
@@ -35,22 +35,36 @@ import static org.mockito.BDDMockito.given;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link GrpcPortInfoApplicationContextInitializer}.
|
||||
* Tests for {@link GrpcServerPortInfoAutoConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class GrpcPortInfoApplicationContextInitializerTests {
|
||||
class GrpcServerPortInfoAutoConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(GrpcServerPortInfoAutoConfiguration.class));
|
||||
|
||||
private static final String PORT_PROPERTY = "local.grpc.server.port";
|
||||
|
||||
@Test
|
||||
void whenServerHasAddressInitializerSetsPortProperty() {
|
||||
void createsGrpcPortInfoApplicationListenerBean() {
|
||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(GrpcPortInfoApplicationListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenNoGrpcServerStartedEventClassDoesNotCreateBean() {
|
||||
this.contextRunner.withClassLoader(new FilteredClassLoader(GrpcServerStartedEvent.class))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(GrpcPortInfoApplicationListener.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenServerHasAddressListenerSetsPortProperty() {
|
||||
NettyGrpcServerFactory factory = mock();
|
||||
testListener(factory, 65535, "65535");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenServerHasNoAddressInitializerSetsNoPortProperty() {
|
||||
void whenServerHasNoAddressListenerSetsNoPortProperty() {
|
||||
NettyGrpcServerFactory factory = mock();
|
||||
testListener(factory, -1, null);
|
||||
}
|
||||
@@ -68,25 +82,14 @@ class GrpcPortInfoApplicationContextInitializerTests {
|
||||
}
|
||||
|
||||
private void testListener(GrpcServerFactory factory, int port, @Nullable String expected) {
|
||||
try (ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(Config.class)) {
|
||||
context.getBean(GrpcPortInfoApplicationContextInitializer.class).initialize(context);
|
||||
this.contextRunner.run((context) -> {
|
||||
GrpcServerLifecycle lifecycle = mock();
|
||||
Server server = mock();
|
||||
given(lifecycle.getFactory()).willReturn(factory);
|
||||
GrpcServerStartedEvent event = new GrpcServerStartedEvent(lifecycle, server, "localhost", port);
|
||||
context.publishEvent(event);
|
||||
assertThat(context.getEnvironment().getProperty(PORT_PROPERTY)).isEqualTo(expected);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Config {
|
||||
|
||||
@Bean
|
||||
GrpcPortInfoApplicationContextInitializer grpcPortInfoApplicationContextInitializer() {
|
||||
return new GrpcPortInfoApplicationContextInitializer();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
+5
-26
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
+7
-27
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user