From 08988c042f754c8b06f038d75fcf6cdc0aad3060 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 16 Jun 2025 09:22:23 +0100 Subject: [PATCH] Add default service config to GrpcClientProperties Ensure that it doesn't conflict with health service configuration. Also ensure random port is used in all tests. Fixes gh-171 (as far as we can) --- .../sample/GrpcServerApplicationTests.java | 3 ++- ...entPropertiesChannelBuilderCustomizer.java | 12 ++++++++--- .../client/GrpcClientProperties.java | 10 ++++++++++ .../client/GrpcClientPropertiesTests.java | 11 ++++++++++ .../GrpcServerAutoConfigurationTests.java | 3 +++ .../GrpcServletAutoConfigurationTests.java | 1 + ...rpcServerHealthAutoConfigurationTests.java | 1 + ...2ResourceServerAutoConfigurationTests.java | 2 +- .../InProcessTestAutoConfigurationTests.java | 20 +++++++++++-------- 9 files changed, 50 insertions(+), 13 deletions(-) diff --git a/samples/grpc-webflux/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java b/samples/grpc-webflux/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java index 33f2f55..0513566 100644 --- a/samples/grpc-webflux/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java +++ b/samples/grpc-webflux/src/test/java/org/springframework/grpc/sample/GrpcServerApplicationTests.java @@ -15,7 +15,8 @@ import org.springframework.grpc.sample.proto.SimpleGrpc; import org.springframework.test.annotation.DirtiesContext; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, - properties = "spring.grpc.client.default-channel.address=0.0.0.0:${local.grpc.port}") + properties = { "spring.grpc.client.default-channel.address=0.0.0.0:${local.grpc.port}", + "spring.grpc.server.port=0" }) @DirtiesContext public class GrpcServerApplicationTests { diff --git a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/ClientPropertiesChannelBuilderCustomizer.java b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/ClientPropertiesChannelBuilderCustomizer.java index 2a7acbe..c284b15 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/ClientPropertiesChannelBuilderCustomizer.java +++ b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/ClientPropertiesChannelBuilderCustomizer.java @@ -15,18 +15,21 @@ */ package org.springframework.grpc.autoconfigure.client; -import io.grpc.ManagedChannelBuilder; import java.time.Duration; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.function.BiConsumer; import java.util.function.Consumer; + import org.springframework.boot.context.properties.PropertyMapper; import org.springframework.grpc.autoconfigure.client.GrpcClientProperties.ChannelConfig; import org.springframework.grpc.client.GrpcChannelBuilderCustomizer; import org.springframework.grpc.client.interceptor.DefaultDeadlineSetupClientInterceptor; import org.springframework.util.unit.DataSize; +import io.grpc.ManagedChannelBuilder; + /** * A {@link GrpcChannelBuilderCustomizer} that maps {@link GrpcClientProperties client * properties} to a channel builder. @@ -58,11 +61,14 @@ class ClientPropertiesChannelBuilderCustomizer defaultServiceConfig = new HashMap(channel.getServiceConfig()); if (channel.getHealth().isEnabled()) { String serviceNameToCheck = channel.getHealth().getServiceName() != null ? channel.getHealth().getServiceName() : ""; - Map healthCheckConfig = Map.of("healthCheckConfig", Map.of("serviceName", serviceNameToCheck)); - builder.defaultServiceConfig(healthCheckConfig); + defaultServiceConfig.put("healthCheckConfig", Map.of("serviceName", serviceNameToCheck)); + } + if (!defaultServiceConfig.isEmpty()) { + builder.defaultServiceConfig(defaultServiceConfig); } if (channel.getDefaultDeadline() != null && channel.getDefaultDeadline().toMillis() > 0L) { builder.intercept(new DefaultDeadlineSetupClientInterceptor(channel.getDefaultDeadline())); diff --git a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientProperties.java b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientProperties.java index 88b10f5..3b66aed 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientProperties.java +++ b/spring-grpc-spring-boot-autoconfigure/src/main/java/org/springframework/grpc/autoconfigure/client/GrpcClientProperties.java @@ -150,6 +150,16 @@ public class GrpcClientProperties implements EnvironmentAware, VirtualTargets { return this.health; } + private final Map serviceConfig = new HashMap<>(); + + /** + * The service config to use for the channel. + * @return the service config + */ + public Map getServiceConfig() { + return this.serviceConfig; + } + /** * The negotiation type for the channel. */ diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/client/GrpcClientPropertiesTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/client/GrpcClientPropertiesTests.java index f81118e..33b0284 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/client/GrpcClientPropertiesTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/client/GrpcClientPropertiesTests.java @@ -169,6 +169,17 @@ class GrpcClientPropertiesTests { assertThat(defaultChannel.getMaxInboundMetadataSize()).isEqualTo(DataSize.ofBytes(256)); } + @Test + void withServiceConfig() { + Map map = new HashMap<>(); + // we have to at least bind one property or bind() fails + map.put("spring.grpc.client.%s.service-config.something.key".formatted("default-channel"), "value"); + GrpcClientProperties properties = bindProperties(map); + var channel = properties.getDefaultChannel(); + assertThat(channel.getServiceConfig()).hasSize(1); + assertThat(channel.getServiceConfig().get("something")).isInstanceOf(Map.class); + } + } @Nested diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfigurationTests.java index cd2f683..4a687bb 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfigurationTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServerAutoConfigurationTests.java @@ -138,6 +138,7 @@ class GrpcServerAutoConfigurationTests { GrpcServiceDiscoverer customGrpcServiceDiscoverer = mock(GrpcServiceDiscoverer.class); this.contextRunnerWithLifecyle() .withBean("customGrpcServiceDiscoverer", GrpcServiceDiscoverer.class, () -> customGrpcServiceDiscoverer) + .withPropertyValues("spring.grpc.server.port=0") .run((context) -> assertThat(context).getBean(GrpcServiceDiscoverer.class) .isSameAs(customGrpcServiceDiscoverer)); } @@ -145,6 +146,7 @@ class GrpcServerAutoConfigurationTests { @Test void grpcServiceDiscovererAutoConfiguredAsExpected() { this.contextRunnerWithLifecyle() + .withPropertyValues("spring.grpc.server.port=0") .run((context) -> assertThat(context).getBean(GrpcServiceDiscoverer.class) .extracting(GrpcServiceDiscoverer::findServices, InstanceOfAssertFactories.list(ServerServiceDefinition.class)) @@ -163,6 +165,7 @@ class GrpcServerAutoConfigurationTests { @Test void grpcServiceConfigurerAutoConfiguredAsExpected() { this.contextRunnerWithLifecyle() + .withPropertyValues("spring.grpc.server.port=0") .run((context) -> assertThat(context).getBean(GrpcServiceConfigurer.class) .isInstanceOf(DefaultGrpcServiceConfigurer.class)); } diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServletAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServletAutoConfigurationTests.java index 322db1d..e732891 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServletAutoConfigurationTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/GrpcServletAutoConfigurationTests.java @@ -77,6 +77,7 @@ class GrpcServletAutoConfigurationTests { void whenGrpcServletNotOnClasspathAutoConfigurationIsSkipped() { this.contextRunner() .withClassLoader(new FilteredClassLoader(GrpcServlet.class)) + .withPropertyValues("spring.grpc.server.port=0") .run((context) -> assertThat(context).doesNotHaveBean(GrpcServletConfiguration.class) .doesNotHaveBean(ServletRegistrationBean.class)); } diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/health/GrpcServerHealthAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/health/GrpcServerHealthAutoConfigurationTests.java index 9ae704c..bcee198 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/health/GrpcServerHealthAutoConfigurationTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/health/GrpcServerHealthAutoConfigurationTests.java @@ -117,6 +117,7 @@ class GrpcServerHealthAutoConfigurationTests { .withBean("grpcServicesDiscoverer", GrpcServiceDiscoverer.class, Mockito::mock) .withBean("sslBundles", SslBundles.class, Mockito::mock) .withBean(BindableService.class, () -> service) + .withPropertyValues("spring.grpc.server.port=0") .run((context) -> assertThatBeanDefinitionsContainInOrder(context, GrpcServerHealthAutoConfiguration.class, GrpcServerFactoryAutoConfiguration.class)); } diff --git a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/OAuth2ResourceServerAutoConfigurationTests.java b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/OAuth2ResourceServerAutoConfigurationTests.java index 64b98e8..98d30f3 100644 --- a/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/OAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-grpc-spring-boot-autoconfigure/src/test/java/org/springframework/grpc/autoconfigure/server/security/OAuth2ResourceServerAutoConfigurationTests.java @@ -116,7 +116,7 @@ class OAuth2ResourceServerAutoConfigurationTests { .withBean(BindableService.class, () -> service) .withBean("noopServerLifecycle", GrpcServerLifecycle.class, Mockito::mock) .withPropertyValues("spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000", - "spring.grpc.server.servlet.enabled=false") + "spring.grpc.server.servlet.enabled=false", "spring.grpc.server.port=0") .run((context) -> { assertThat(context).hasSingleBean(AuthenticationProcessInterceptor.class); }); diff --git a/spring-grpc-test/src/test/java/org/springframework/grpc/test/InProcessTestAutoConfigurationTests.java b/spring-grpc-test/src/test/java/org/springframework/grpc/test/InProcessTestAutoConfigurationTests.java index 9ac8d32..f3215ad 100644 --- a/spring-grpc-test/src/test/java/org/springframework/grpc/test/InProcessTestAutoConfigurationTests.java +++ b/spring-grpc-test/src/test/java/org/springframework/grpc/test/InProcessTestAutoConfigurationTests.java @@ -62,7 +62,8 @@ class InProcessTestAutoConfigurationTests { @Test void whenTestInProcessEnabledPropIsSetToTrueDoesAutoConfigureBeans() { this.contextRunner() - .withPropertyValues("spring.grpc.test.inprocess.enabled=true", "spring.grpc.server.inprocess.name=foo") + .withPropertyValues("spring.grpc.test.inprocess.enabled=true", "spring.grpc.server.inprocess.name=foo", + "spring.grpc.server.port=0") .run((context) -> { assertThat(context).getBeans(GrpcServerFactory.class) .containsOnlyKeys("testInProcessGrpcServerFactory", "nettyGrpcServerFactory"); @@ -73,18 +74,21 @@ class InProcessTestAutoConfigurationTests { @Test void whenTestInProcessEnabledPropIsNotSetDoesNotAutoConfigureBeans() { - this.contextRunner().withPropertyValues("spring.grpc.server.inprocess.name=foo").run((context) -> { - assertThat(context).getBeans(GrpcServerFactory.class) - .containsOnlyKeys("inProcessGrpcServerFactory", "nettyGrpcServerFactory"); - assertThat(context).getBeans(GrpcChannelFactory.class) - .containsOnlyKeys("inProcessGrpcChannelFactory", "nettyGrpcChannelFactory"); - }); + this.contextRunner() + .withPropertyValues("spring.grpc.server.inprocess.name=foo", "spring.grpc.server.port=0") + .run((context) -> { + assertThat(context).getBeans(GrpcServerFactory.class) + .containsOnlyKeys("inProcessGrpcServerFactory", "nettyGrpcServerFactory"); + assertThat(context).getBeans(GrpcChannelFactory.class) + .containsOnlyKeys("inProcessGrpcChannelFactory", "nettyGrpcChannelFactory"); + }); } @Test void whenTestInProcessEnabledPropIsSetToFalseDoesNotAutoConfigureBeans() { this.contextRunner() - .withPropertyValues("spring.grpc.test.inprocess.enabled=false", "spring.grpc.server.inprocess.name=foo") + .withPropertyValues("spring.grpc.test.inprocess.enabled=false", "spring.grpc.server.inprocess.name=foo", + "spring.grpc.server.port=0") .run((context) -> { assertThat(context).getBeans(GrpcServerFactory.class) .containsOnlyKeys("inProcessGrpcServerFactory", "nettyGrpcServerFactory");