Skip to content

Commit a653f22

Browse files
committed
Fix codec configuration (server side)
- only use default de/compressor registry when user provides no custom de/compressor - update tests accordingly Signed-off-by: onobc <chris.bono@gmail.com>
1 parent b3ee513 commit a653f22

File tree

4 files changed

+143
-8
lines changed

4 files changed

+143
-8
lines changed

module/spring-boot-grpc-client/src/test/java/org/springframework/boot/grpc/client/autoconfigure/GrpcClientAutoConfigurationTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ void decompressionCustomizerAutoConfiguredAsExpected() {
201201
}
202202

203203
@Test
204-
void whenNoDecompressorRegistryAutoConfigurationIsSkipped() {
204+
void whenNoDecompressorRegistryThenDecompressionCustomizerIsNotConfigured() {
205205
// Codec class guards the imported GrpcCodecConfiguration which provides the
206206
// registry
207207
this.contextRunner()

module/spring-boot-grpc-server/src/main/java/org/springframework/boot/grpc/server/autoconfigure/GrpcCodecConfiguration.java

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.grpc.CompressorRegistry;
2222
import io.grpc.Decompressor;
2323
import io.grpc.DecompressorRegistry;
24+
import io.grpc.ServerBuilder;
2425

2526
import org.springframework.beans.factory.ObjectProvider;
2627
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
@@ -37,19 +38,44 @@
3738
@ConditionalOnClass(Codec.class)
3839
class GrpcCodecConfiguration {
3940

41+
/**
42+
* The compressor registry that is set on the
43+
* {@link ServerBuilder#compressorRegistry(CompressorRegistry) server builder} .
44+
* @param compressors the compressors to use on the registry
45+
* @return a new {@link CompressorRegistry#newEmptyInstance() registry} with the
46+
* specified compressors or the {@link CompressorRegistry#getDefaultInstance() default
47+
* registry} if no custom compressors are available in the application context.
48+
*/
4049
@Bean
4150
@ConditionalOnMissingBean
4251
CompressorRegistry compressorRegistry(ObjectProvider<Compressor> compressors) {
43-
CompressorRegistry registry = CompressorRegistry.getDefaultInstance();
52+
if (compressors.stream().count() == 0) {
53+
return CompressorRegistry.getDefaultInstance();
54+
}
55+
CompressorRegistry registry = CompressorRegistry.newEmptyInstance();
4456
compressors.orderedStream().forEachOrdered(registry::register);
4557
return registry;
4658
}
4759

60+
/**
61+
* The decompressor registry that is set on the
62+
* {@link ServerBuilder#decompressorRegistry(DecompressorRegistry) server builder}.
63+
* @param decompressors the decompressors to use on the registry
64+
* @return a new {@link DecompressorRegistry#emptyInstance() registry} with the
65+
* specified decompressors or the {@link DecompressorRegistry#getDefaultInstance()
66+
* default registry} if no custom decompressors are available in the application
67+
* context.
68+
*/
4869
@Bean
4970
@ConditionalOnMissingBean
5071
DecompressorRegistry decompressorRegistry(ObjectProvider<Decompressor> decompressors) {
51-
DecompressorRegistry registry = DecompressorRegistry.getDefaultInstance();
52-
decompressors.orderedStream().forEachOrdered((decompressor) -> registry.with(decompressor, false));
72+
if (decompressors.stream().count() == 0) {
73+
return DecompressorRegistry.getDefaultInstance();
74+
}
75+
DecompressorRegistry registry = DecompressorRegistry.emptyInstance();
76+
for (Decompressor decompressor : decompressors.orderedStream().toList()) {
77+
registry = registry.with(decompressor, false);
78+
}
5379
return registry;
5480
}
5581

module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcCodecConfigurationTests.java

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@
1616

1717
package org.springframework.boot.grpc.server.autoconfigure;
1818

19+
import io.grpc.Codec;
20+
import io.grpc.Compressor;
1921
import io.grpc.CompressorRegistry;
22+
import io.grpc.Decompressor;
2023
import io.grpc.DecompressorRegistry;
2124
import org.junit.jupiter.api.Test;
2225

2326
import org.springframework.boot.autoconfigure.AutoConfigurations;
27+
import org.springframework.boot.test.context.FilteredClassLoader;
2428
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
2529

2630
import static org.assertj.core.api.Assertions.assertThat;
31+
import static org.mockito.BDDMockito.given;
32+
import static org.mockito.Mockito.mock;
2733

2834
/**
2935
* Tests for {@link GrpcCodecConfiguration}.
@@ -36,13 +42,59 @@ class GrpcCodecConfigurationTests {
3642
.withConfiguration(AutoConfigurations.of(GrpcCodecConfiguration.class));
3743

3844
@Test
39-
void testCompressorRegistryBean() {
40-
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(CompressorRegistry.class));
45+
void whenCodecNotOnClasspathThenAutoconfigurationSkipped() {
46+
this.contextRunner.withClassLoader(new FilteredClassLoader(Codec.class))
47+
.run((context) -> assertThat(context).doesNotHaveBean(GrpcCodecConfiguration.class));
4148
}
4249

4350
@Test
44-
void testDecompressorRegistryBean() {
45-
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(DecompressorRegistry.class));
51+
void whenHasCustomCompressorRegistryDoesNotAutoConfigureBean() {
52+
CompressorRegistry customRegistry = mock();
53+
this.contextRunner.withBean("customCompressorRegistry", CompressorRegistry.class, () -> customRegistry)
54+
.run((context) -> assertThat(context).getBean(CompressorRegistry.class).isSameAs(customRegistry));
55+
}
56+
57+
@Test
58+
void compressorRegistryAutoConfiguredAsExpected() {
59+
this.contextRunner.run((context) -> assertThat(context).getBean(CompressorRegistry.class)
60+
.isSameAs(CompressorRegistry.getDefaultInstance()));
61+
}
62+
63+
@Test
64+
void whenCustomCompressorsThenCompressorRegistryIsNewInstance() {
65+
Compressor compressor = mock();
66+
given(compressor.getMessageEncoding()).willReturn("foo");
67+
this.contextRunner.withBean(Compressor.class, () -> compressor).run((context) -> {
68+
assertThat(context).hasSingleBean(CompressorRegistry.class);
69+
CompressorRegistry registry = context.getBean(CompressorRegistry.class);
70+
assertThat(registry).isNotSameAs(CompressorRegistry.getDefaultInstance());
71+
assertThat(registry.lookupCompressor("foo")).isSameAs(compressor);
72+
});
73+
}
74+
75+
@Test
76+
void whenHasCustomDecompressorRegistryDoesNotAutoConfigureBean() {
77+
DecompressorRegistry customRegistry = mock();
78+
this.contextRunner.withBean("customDecompressorRegistry", DecompressorRegistry.class, () -> customRegistry)
79+
.run((context) -> assertThat(context).getBean(DecompressorRegistry.class).isSameAs(customRegistry));
80+
}
81+
82+
@Test
83+
void decompressorRegistryAutoConfiguredAsExpected() {
84+
this.contextRunner.run((context) -> assertThat(context).getBean(DecompressorRegistry.class)
85+
.isSameAs(DecompressorRegistry.getDefaultInstance()));
86+
}
87+
88+
@Test
89+
void whenCustomDecompressorsThenDecompressorRegistryIsNewInstance() {
90+
Decompressor decompressor = mock();
91+
given(decompressor.getMessageEncoding()).willReturn("foo");
92+
this.contextRunner.withBean(Decompressor.class, () -> decompressor).run((context) -> {
93+
assertThat(context).hasSingleBean(DecompressorRegistry.class);
94+
DecompressorRegistry registry = context.getBean(DecompressorRegistry.class);
95+
assertThat(registry).isNotSameAs(DecompressorRegistry.getDefaultInstance());
96+
assertThat(registry.lookupDecompressor("foo")).isSameAs(decompressor);
97+
});
4698
}
4799

48100
}

module/spring-boot-grpc-server/src/test/java/org/springframework/boot/grpc/server/autoconfigure/GrpcServerAutoConfigurationTests.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
import java.util.concurrent.TimeUnit;
2222

2323
import io.grpc.BindableService;
24+
import io.grpc.Codec;
25+
import io.grpc.CompressorRegistry;
26+
import io.grpc.DecompressorRegistry;
2427
import io.grpc.Grpc;
2528
import io.grpc.ServerBuilder;
2629
import io.grpc.ServerServiceDefinition;
@@ -61,6 +64,7 @@
6164
import static org.mockito.ArgumentMatchers.any;
6265
import static org.mockito.ArgumentMatchers.anyInt;
6366
import static org.mockito.BDDMockito.given;
67+
import static org.mockito.BDDMockito.then;
6468
import static org.mockito.Mockito.inOrder;
6569
import static org.mockito.Mockito.mock;
6670

@@ -409,6 +413,59 @@ void nettyServerFactoryAutoConfiguredWithSsl() {
409413
NettyGrpcServerFactory.class, "myhost:6160", "nettyGrpcServerLifecycle");
410414
}
411415

416+
@Nested
417+
class WithCodecConfiguration {
418+
419+
@SuppressWarnings("unchecked")
420+
@Test
421+
void compressionCustomizerAutoConfiguredAsExpected() {
422+
GrpcServerAutoConfigurationTests.this.contextRunner().run((context) -> {
423+
assertThat(context).getBean("compressionServerConfigurer", ServerBuilderCustomizer.class).isNotNull();
424+
var customizer = context.getBean("compressionServerConfigurer", ServerBuilderCustomizer.class);
425+
var compressorRegistry = context.getBean(CompressorRegistry.class);
426+
ServerBuilder<?> builder = mock();
427+
customizer.customize(builder);
428+
then(builder).should().compressorRegistry(compressorRegistry);
429+
});
430+
}
431+
432+
@Test
433+
void whenNoCompressorRegistryThenCompressionCustomizerIsNotConfigured() {
434+
// Codec class guards the imported GrpcCodecConfiguration which provides the
435+
// registry
436+
GrpcServerAutoConfigurationTests.this.contextRunner()
437+
.withClassLoader(new FilteredClassLoader(Codec.class))
438+
.run((context) -> assertThat(context)
439+
.getBean("compressionServerConfigurer", ServerBuilderCustomizer.class)
440+
.isNull());
441+
}
442+
443+
@SuppressWarnings("unchecked")
444+
@Test
445+
void decompressionCustomizerAutoConfiguredAsExpected() {
446+
GrpcServerAutoConfigurationTests.this.contextRunner().run((context) -> {
447+
assertThat(context).getBean("decompressionServerConfigurer", ServerBuilderCustomizer.class).isNotNull();
448+
var customizer = context.getBean("decompressionServerConfigurer", ServerBuilderCustomizer.class);
449+
var decompressorRegistry = context.getBean(DecompressorRegistry.class);
450+
ServerBuilder<?> builder = mock();
451+
customizer.customize(builder);
452+
then(builder).should().decompressorRegistry(decompressorRegistry);
453+
});
454+
}
455+
456+
@Test
457+
void whenNoDecompressorRegistryThenDecompressionCustomizerIsNotConfigured() {
458+
// Codec class guards the imported GrpcCodecConfiguration which provides the
459+
// registry
460+
GrpcServerAutoConfigurationTests.this.contextRunner()
461+
.withClassLoader(new FilteredClassLoader(Codec.class))
462+
.run((context) -> assertThat(context)
463+
.getBean("decompressionClientCustomizer", ServerBuilderCustomizer.class)
464+
.isNull());
465+
}
466+
467+
}
468+
412469
@Nested
413470
class WithAllFactoriesServiceFilterAutoConfig {
414471

0 commit comments

Comments
 (0)