Skip to content

spring-boot-starter-grpc-server ignores spring.grpc.server.inprocess.name for tests #50860

Description

@SledgeHammer01

My working 1.0.3 setup:

    <dependency>
      <groupId>org.springframework.grpc</groupId>
      <artifactId>spring-grpc-server-spring-boot-starter</artifactId>
      <version>1.0.3</version>
      <optional>true</optional>
    </dependency>
    <dependency>
      <groupId>org.springframework.grpc</groupId>
      <artifactId>spring-grpc-test</artifactId>
      <version>${spring-grpc.version}</version>
      <optional>true</optional>
    </dependency>

Test class:

@ExtensionMethod({WebTestClientExtensions.class, GrpcClientExtensions.class})
@WebFluxTest
@AutoConfigureInProcessTransport
@ImportAutoConfiguration({
  ReactiveWebSecurityAutoConfiguration.class,
  GrpcServerAutoConfiguration.class,
  GrpcServerFactoryAutoConfiguration.class
})
public class GrpcIntegrationTests extends AbstractGrpcIntegrationTests {

  private static final String TEST_FIXTURES_FOLDER = "test-fixtures/grpc/";

  @SpringBootConfiguration
  @EnableAutoConfiguration
  static class TestApplication extends AbstractGrpcTestApplication {}

  GrpcIntegrationTests() {
    super(TEST_FIXTURES_FOLDER);
  }

  @Nested
  @ActiveProfiles("oauth2-disabled")
  class GrpcOAuth2DisabledTests extends AbstractGrpcIntegrationTests {


    GrpcOAuth2DisabledTests() {
      super(TEST_FIXTURES_FOLDER);
    }

Abstract class:

@ContextConfiguration(
    initializers = AbstractGrpcIntegrationTests.GrpcApplicationContextInitializer.class)
@TestPropertySource(
    properties = {})
public abstract class AbstractGrpcIntegrationTests extends AbstractApiReactiveIntegrationTests {

  @SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
  @Autowired
  protected ReactorGrpcTestServiceGrpc.ReactorGrpcTestServiceStub stub;

  protected AbstractGrpcIntegrationTests(String testFixturesFolder) {
    super(testFixturesFolder);
  }

  public static final class GrpcApplicationContextInitializer
      implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    @Override
    public void initialize(@NonNull ConfigurableApplicationContext applicationContext) {
      TestPropertyValues.of("spring.grpc.server.inprocess.name=test-inprocess-" + UUID.randomUUID())
          .applyTo(applicationContext);
    }
  }

  protected abstract static class AbstractGrpcTestApplication extends AbstractTestApplication {

    @Bean
    public GrpcTestService grpcTestService() {
      return new GrpcTestService();
    }

    @Bean
    public ReactorGrpcTestServiceGrpc.ReactorGrpcTestServiceStub stub(
        GrpcChannelFactory channels,
        @Value("${spring.grpc.server.inprocess.name}") String name) {
      return ReactorGrpcTestServiceGrpc.newReactorStub(channels.createChannel(name));
    }
  }
}

So the idea was that the @Nested tests would each create a test-inprocess- instead and wire up the stub.

Now I'm trying to get this to work with:

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-grpc-server</artifactId>
      <optional>true</optional>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-grpc-server-test</artifactId>
      <optional>true</optional>
    </dependency>

new test class preamble:

@ExtensionMethod({WebTestClientExtensions.class, GrpcClientExtensions.class})
@WebFluxTest
@AutoConfigureTestGrpcTransport
@ImportAutoConfiguration({
  ReactiveWebSecurityAutoConfiguration.class,
  GrpcServerAutoConfiguration.class
})

The top level test class works fine, but @Nested classes fail with:

Caused by: java.io.IOException: name already registered: 3f6df1c8-474e-47ea-9995-acf6d64baff4

Seems like it is ignoring the spring.grpc.server.inprocess.name property and/or starting up duplicate instances.

I read the migration guide and didn't see anything around this.

Except maybe this blurb:

Test Specific Factory Classes
Tests now use a custom GrpcServerFactory to create in-process channels rather than using InProcessGrpcServerFactory. This helps keep InProcessGrpcServerFactory for user code and allow better detection of then a factory is for test purposes.

but not much information on it.

Trying to debug, it only gets into InProcessGrpcServerConfiguration if I use:

@AutoConfigureTestGrpcTransport(enableServerFactory = true)

Then it uses my custom names, but it still tries to create the inprocess server with the plain guid which I assume is the spring boot one.

EDIT: Seems to be an oversight with TestGrpcTransportAutoConfiguration not respecting the custom name. If I exclude it and then c&p TestGrpcChannelFactory into my code and create these 3 beans:

    @Bean
    ClientInterceptorsConfigurer grpcClientInterceptorsConfigurer(ApplicationContext applicationContext) {
      return new ClientInterceptorsConfigurer(applicationContext);
    }

    @Bean
    public SslBundles sslBundles() {
      SslBundle sslBundle = SslBundle.of(SslStoreBundle.NONE);
      return new DefaultSslBundleRegistry("grpc", sslBundle);
    }

    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    TestGrpcChannelFactory testGrpcChannelFactory(ClientInterceptorsConfigurer interceptorsConfigurer, @Value("${spring.grpc.server.inprocess.name}") String name) {
      return new TestGrpcChannelFactory(name, interceptorsConfigurer);
    }

Then it works, so the problem seems to be that you're using private static final String address = InProcessServerBuilder.generateName(); and ignoring the property.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions