Skip to content

Commit 4cd7430

Browse files
committed
Polish "Allow filtering of services"
This commit updates some tests and the contract slightly of the previous commit to allow a serverFactory parameter as part of the inputs to the service filter and tests all variants of server factories via `@ParameterizedTest` See #207 Signed-off-by: Chris Bono <[email protected]>
1 parent 0fccea1 commit 4cd7430

File tree

6 files changed

+176
-42
lines changed

6 files changed

+176
-42
lines changed

spring-grpc-core/src/main/java/org/springframework/grpc/server/DefaultGrpcServerFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public Server createServer() {
100100

101101
@Override
102102
public void addService(ServerServiceDefinition service) {
103-
if (this.serviceFilter == null || this.serviceFilter.filter(service)) {
103+
if (this.serviceFilter == null || this.serviceFilter.filter(service, this)) {
104104
this.serviceList.add(service);
105105
}
106106
}

spring-grpc-core/src/main/java/org/springframework/grpc/server/ServerServiceDefinitionFilter.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,21 @@
1818
import io.grpc.ServerServiceDefinition;
1919

2020
/**
21-
* Strategy to determine whether a {@link ServerServiceDefinition} should be included for
22-
* the {@link GrpcServerFactory server factory}.
21+
* Strategy to determine whether a {@link ServerServiceDefinition} should be added to a
22+
* {@link GrpcServerFactory server factory}.
2323
*
2424
* @author Andrey Litvitski
2525
*/
2626
@FunctionalInterface
2727
public interface ServerServiceDefinitionFilter {
2828

2929
/**
30-
* Determine whether the given {@link ServerServiceDefinition} should be included for
31-
* the {@link GrpcServerFactory server factory}.
30+
* Determine whether the given {@link ServerServiceDefinition} should be added to the
31+
* given {@link GrpcServerFactory server factory}.
3232
* @param serviceDefinition the gRPC service definition under consideration.
33+
* @param serverFactory the server factory in use.
3334
* @return {@code true} if the service should be included; {@code false} otherwise.
3435
*/
35-
boolean filter(ServerServiceDefinition serviceDefinition);
36+
boolean filter(ServerServiceDefinition serviceDefinition, GrpcServerFactory serverFactory);
3637

3738
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2024-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.grpc.server;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.mockito.Mockito.mock;
21+
22+
import java.util.List;
23+
24+
import org.assertj.core.api.InstanceOfAssertFactories;
25+
import org.junit.jupiter.api.Nested;
26+
import org.junit.jupiter.api.Test;
27+
28+
import io.grpc.ServerServiceDefinition;
29+
30+
/**
31+
* Tests for {@link DefaultGrpcServerFactory}.
32+
*/
33+
class DefaultGrpcServerFactoryTests {
34+
35+
@Nested
36+
class WithServiceFilter {
37+
38+
@Test
39+
void whenNoFilterThenAllServicesAdded() {
40+
ServerServiceDefinition serviceDef1 = mock();
41+
ServerServiceDefinition serviceDef2 = mock();
42+
DefaultGrpcServerFactory serverFactory = new DefaultGrpcServerFactory("myhost:5150", List.of(), null, null,
43+
null, null);
44+
serverFactory.addService(serviceDef2);
45+
serverFactory.addService(serviceDef1);
46+
assertThat(serverFactory)
47+
.extracting("serviceList", InstanceOfAssertFactories.list(ServerServiceDefinition.class))
48+
.containsExactly(serviceDef2, serviceDef1);
49+
}
50+
51+
@Test
52+
void whenFilterAllowsAllThenAllServicesAdded() {
53+
ServerServiceDefinition serviceDef1 = mock();
54+
ServerServiceDefinition serviceDef2 = mock();
55+
ServerServiceDefinitionFilter serviceFilter = (serviceDef, serviceFactory) -> true;
56+
DefaultGrpcServerFactory serverFactory = new DefaultGrpcServerFactory("myhost:5150", List.of(), null, null,
57+
null, serviceFilter);
58+
serverFactory.addService(serviceDef2);
59+
serverFactory.addService(serviceDef1);
60+
assertThat(serverFactory)
61+
.extracting("serviceList", InstanceOfAssertFactories.list(ServerServiceDefinition.class))
62+
.containsExactly(serviceDef2, serviceDef1);
63+
}
64+
65+
@Test
66+
void whenFilterAllowsOneThenOneServiceAdded() {
67+
ServerServiceDefinition serviceDef1 = mock();
68+
ServerServiceDefinition serviceDef2 = mock();
69+
ServerServiceDefinitionFilter serviceFilter = (serviceDef, serviceFactory) -> serviceDef == serviceDef1;
70+
DefaultGrpcServerFactory serverFactory = new DefaultGrpcServerFactory("myhost:5150", List.of(), null, null,
71+
null, serviceFilter);
72+
serverFactory.addService(serviceDef2);
73+
serverFactory.addService(serviceDef1);
74+
assertThat(serverFactory)
75+
.extracting("serviceList", InstanceOfAssertFactories.list(ServerServiceDefinition.class))
76+
.containsExactly(serviceDef1);
77+
}
78+
79+
}
80+
81+
}

spring-grpc-core/src/test/java/org/springframework/grpc/server/GrpcServerFactoryTests.java

Lines changed: 0 additions & 30 deletions
This file was deleted.

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

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.grpc.autoconfigure.server;
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.junit.jupiter.params.provider.Arguments.arguments;
2021
import static org.mockito.ArgumentMatchers.any;
2122
import static org.mockito.ArgumentMatchers.anyInt;
2223
import static org.mockito.Mockito.inOrder;
@@ -26,11 +27,16 @@
2627
import java.time.Duration;
2728
import java.util.List;
2829
import java.util.concurrent.TimeUnit;
30+
import java.util.function.Function;
31+
import java.util.stream.Stream;
2932

3033
import org.assertj.core.api.InstanceOfAssertFactories;
3134
import org.junit.jupiter.api.BeforeEach;
3235
import org.junit.jupiter.api.Nested;
3336
import org.junit.jupiter.api.Test;
37+
import org.junit.jupiter.params.ParameterizedTest;
38+
import org.junit.jupiter.params.provider.Arguments;
39+
import org.junit.jupiter.params.provider.MethodSource;
3440
import org.mockito.InOrder;
3541
import org.mockito.MockedStatic;
3642
import org.mockito.Mockito;
@@ -45,7 +51,6 @@
4551
import org.springframework.context.annotation.Bean;
4652
import org.springframework.context.annotation.Configuration;
4753
import org.springframework.core.annotation.Order;
48-
import org.springframework.grpc.server.DefaultGrpcServerFactory;
4954
import org.springframework.grpc.server.GrpcServerFactory;
5055
import org.springframework.grpc.server.InProcessGrpcServerFactory;
5156
import org.springframework.grpc.server.NettyGrpcServerFactory;
@@ -83,13 +88,23 @@ void prepareForTest() {
8388
when(service.bindService()).thenReturn(serviceDefinition);
8489
}
8590

86-
private AbstractApplicationContextRunner<?, ?, ?> contextRunner() {
91+
private ApplicationContextRunner contextRunner() {
8792
// NOTE: we use noop server lifecycle to avoid startup
8893
ApplicationContextRunner runner = new ApplicationContextRunner();
8994
return contextRunner(runner);
9095
}
9196

92-
private AbstractApplicationContextRunner<?, ?, ?> contextRunner(AbstractApplicationContextRunner<?, ?, ?> runner) {
97+
private ApplicationContextRunner contextRunner(ApplicationContextRunner runner) {
98+
return runner
99+
.withConfiguration(AutoConfigurations.of(GrpcServerAutoConfiguration.class,
100+
GrpcServerFactoryAutoConfiguration.class, SslAutoConfiguration.class))
101+
.withBean("shadedNettyGrpcServerLifecycle", GrpcServerLifecycle.class, Mockito::mock)
102+
.withBean("nettyGrpcServerLifecycle", GrpcServerLifecycle.class, Mockito::mock)
103+
.withBean("inProcessGrpcServerLifecycle", GrpcServerLifecycle.class, Mockito::mock)
104+
.withBean(BindableService.class, () -> service);
105+
}
106+
107+
private WebApplicationContextRunner webContextRunner(WebApplicationContextRunner runner) {
93108
return runner
94109
.withConfiguration(AutoConfigurations.of(GrpcServerAutoConfiguration.class,
95110
GrpcServerFactoryAutoConfiguration.class, SslAutoConfiguration.class))
@@ -294,7 +309,7 @@ void shadedNettyServerFactoryAutoConfiguredAsExpected() {
294309
@Test
295310
void serverFactoryAutoConfiguredInWebAppWhenServletDisabled() {
296311
serverFactoryAutoConfiguredAsExpected(
297-
this.contextRunner(new WebApplicationContextRunner())
312+
this.webContextRunner(new WebApplicationContextRunner())
298313
.withPropertyValues("spring.grpc.server.host=myhost", "spring.grpc.server.port=6160")
299314
.withPropertyValues("spring.grpc.server.servlet.enabled=false"),
300315
GrpcServerFactory.class, "myhost:6160", "shadedNettyGrpcServerLifecycle");
@@ -395,6 +410,74 @@ void nettyServerFactoryAutoConfiguredWithSsl() {
395410
NettyGrpcServerFactory.class, "myhost:6160", "nettyGrpcServerLifecycle");
396411
}
397412

413+
@Nested
414+
class WithAllFactoriesServiceFilterAutoConfig {
415+
416+
static Stream<Arguments> serverFactoryProvider() {
417+
return Stream.of(arguments(
418+
(Function<ApplicationContextRunner, ApplicationContextRunner>) (contextRunner) -> contextRunner,
419+
ShadedNettyGrpcServerFactory.class),
420+
arguments(
421+
(Function<ApplicationContextRunner, ApplicationContextRunner>) (
422+
contextRunner) -> contextRunner.withClassLoader(new FilteredClassLoader(
423+
io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class)),
424+
NettyGrpcServerFactory.class),
425+
arguments(
426+
(Function<ApplicationContextRunner, ApplicationContextRunner>) (
427+
contextRunner) -> contextRunner
428+
.withPropertyValues("spring.grpc.server.inprocess.name=foo")
429+
.withClassLoader(new FilteredClassLoader(NettyServerBuilder.class,
430+
io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder.class)),
431+
InProcessGrpcServerFactory.class));
432+
}
433+
434+
@ParameterizedTest(name = "whenNoServiceFilterThenFactoryUsesNoFilter w/ factory {1}")
435+
@MethodSource("serverFactoryProvider")
436+
void whenNoServiceFilterThenFactoryUsesNoFilter(
437+
Function<ApplicationContextRunner, ApplicationContextRunner> serverFactoryContextCustomizer,
438+
Class<?> expectedServerFactoryType) {
439+
GrpcServerAutoConfigurationTests.this.contextRunner()
440+
.withPropertyValues("spring.grpc.server.port=0")
441+
.with(serverFactoryContextCustomizer)
442+
.run((context) -> assertThat(context).getBean(GrpcServerFactory.class)
443+
.isInstanceOf(expectedServerFactoryType)
444+
.extracting("serviceFilter")
445+
.isNull());
446+
}
447+
448+
@ParameterizedTest(name = "whenUniqueServiceFilterThenFactoryUsesFilter w/ factory {1}")
449+
@MethodSource("serverFactoryProvider")
450+
void whenUniqueServiceFilterThenFactoryUsesFilter(
451+
Function<ApplicationContextRunner, ApplicationContextRunner> serverFactoryContextCustomizer,
452+
Class<?> expectedServerFactoryType) {
453+
ServerServiceDefinitionFilter serviceFilter = mock();
454+
GrpcServerAutoConfigurationTests.this.contextRunner()
455+
.withPropertyValues("spring.grpc.server.port=0")
456+
.withBean(ServerServiceDefinitionFilter.class, () -> serviceFilter)
457+
.with(serverFactoryContextCustomizer)
458+
.run((context) -> assertThat(context).getBean(GrpcServerFactory.class)
459+
.isInstanceOf(expectedServerFactoryType)
460+
.extracting("serviceFilter")
461+
.isSameAs(serviceFilter));
462+
}
463+
464+
@ParameterizedTest(name = "whenMultipleServiceFiltersThenThrowsException w/ factory {1}")
465+
@MethodSource("serverFactoryProvider")
466+
void whenMultipleServiceFiltersThenThrowsException(
467+
Function<ApplicationContextRunner, ApplicationContextRunner> serverFactoryContextCustomizer,
468+
Class<?> ignored) {
469+
GrpcServerAutoConfigurationTests.this.contextRunnerWithLifecyle()
470+
.withPropertyValues("spring.grpc.server.port=0")
471+
.withBean("filter1", ServerServiceDefinitionFilter.class, Mockito::mock)
472+
.withBean("filter2", ServerServiceDefinitionFilter.class, Mockito::mock)
473+
.with(serverFactoryContextCustomizer)
474+
.run((context) -> assertThat(context).hasFailed()
475+
.getFailure()
476+
.hasMessageContaining("expected single matching bean but found 2: filter1,filter2"));
477+
}
478+
479+
}
480+
398481
@Nested
399482
class WithGrpcServiceConfigurerAutoConfig {
400483

spring-grpc-test/src/main/java/org/springframework/grpc/test/InProcessTestAutoConfiguration.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public class InProcessTestAutoConfiguration {
5757
@ConditionalOnBean(BindableService.class)
5858
@Order(Ordered.HIGHEST_PRECEDENCE)
5959
TestInProcessGrpcServerFactory testInProcessGrpcServerFactory(GrpcServiceDiscoverer serviceDiscoverer,
60-
GrpcServiceConfigurer serviceConfigurer,
61-
List<ServerBuilderCustomizer<InProcessServerBuilder>> customizers,
60+
GrpcServiceConfigurer serviceConfigurer, List<ServerBuilderCustomizer<InProcessServerBuilder>> customizers,
6261
@Nullable ServerServiceDefinitionFilter serviceFilter) {
6362
var factory = new TestInProcessGrpcServerFactory(address, customizers, serviceFilter);
6463
serviceDiscoverer.findServices()

0 commit comments

Comments
 (0)