From b3f84d1ee2b7e26c514ef43b6e108fe6ad530a71 Mon Sep 17 00:00:00 2001 From: ST-DDT Date: Mon, 2 Nov 2020 21:59:52 +0100 Subject: [PATCH] Modify default channel factory to add support for 'null' schemes (Fixes #419) --- docs/en/client/configuration.md | 5 + docs/en/client/testing.md | 26 +++++ .../GrpcClientAutoConfiguration.java | 17 ++- .../channelfactory/GrpcChannelFactory.java | 9 +- .../InProcessChannelFactory.java | 20 +++- .../InProcessOrAlternativeChannelFactory.java | 103 ------------------ .../channelfactory/NullChannelFactory.java | 50 +++++++++ .../SchemaAwareChannelFactory.java | 96 ++++++++++++++++ .../inject/GrpcClientBeanPostProcessor.java | 2 +- ...a => AbstractGrpcClientInjectionTest.java} | 71 ++++++------ ...faultInProcessGrpcClientInjectionTest.java | 42 +++++++ .../DefaultNettyGrpcClientInjectionTest.java | 40 +++++++ .../DefaultNullGrpcClientInjectionTest.java | 49 +++++++++ .../inject/InProcessClientInjectionTest.java | 41 +++++++ 14 files changed, 417 insertions(+), 154 deletions(-) delete mode 100644 grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessOrAlternativeChannelFactory.java create mode 100644 grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/NullChannelFactory.java create mode 100644 grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/SchemaAwareChannelFactory.java rename tests/src/test/java/net/devh/boot/grpc/test/inject/{GrpcClientInjectionTest.java => AbstractGrpcClientInjectionTest.java} (68%) create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultInProcessGrpcClientInjectionTest.java create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNettyGrpcClientInjectionTest.java create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNullGrpcClientInjectionTest.java create mode 100644 tests/src/test/java/net/devh/boot/grpc/test/inject/InProcessClientInjectionTest.java diff --git a/docs/en/client/configuration.md b/docs/en/client/configuration.md index daf7564a9..e379aeb79 100644 --- a/docs/en/client/configuration.md +++ b/docs/en/client/configuration.md @@ -76,6 +76,11 @@ There are a number of supported schemes, that you can use to determine the targe This is a special scheme that will bypass the normal channel factory and will use the `InProcessChannelFactory` instead. Use it to connect to the [`InProcessServer`](../server/configuration.md#enabling-the-inprocessserver). \ Example: `in-process:foobar` +- `null`: \ + This is a special scheme that will bypass the normal channel factory and will use the `NullChannelFactory` + instead. Use it to use `null` for a GrpcClient annotated field. \ + Useful for testing. \ + Example: `null:/` - *custom*: \ You can define custom [`NameResolverProvider`s](https://javadoc.io/page/io.grpc/grpc-all/latest/io/grpc/NameResolverProvider.html) those diff --git a/docs/en/client/testing.md b/docs/en/client/testing.md index a92e5f704..c50d9011c 100644 --- a/docs/en/client/testing.md +++ b/docs/en/client/testing.md @@ -11,6 +11,7 @@ This section describes how you write tests for components that use the `@GrpcCli - [Useful Dependencies](#useful-dependencies) - [Using a Mocked Stub](#using-a-mocked-stub) - [Running a Dummy Server](#running-a-dummy-server) +- [Skipping injection](#skipping-injection) ## Additional Topics @@ -254,6 +255,31 @@ public class ChatServiceImplForMyComponentIntegrationTest extends ChatServiceGrp } ```` +## Skipping injection + +If you don't need a specific `@GrpcClient` in a test, then you can configure it to be skipped using the `null` scheme. +(In that case it will be injected with `null`) + +````java +@SpringBootTest(properties = { + "grpc.client.test.address=null:/", +}, ...) +class MyTest { + + @GrpcClient("test") + Channel channel; + + @Test() + void test() { + assertNull(channel); + } + +} +```` + +> **Note:** Due to configuration limitations you cannot use just `null` or `null:` as address, +> you have to specify a scheme specific part e.g.: `null:/` or `null:null`. + ## Additional Topics - [Getting Started](getting-started.md) diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java index 64dbddbb2..ebcc318f0 100644 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/autoconfigure/GrpcClientAutoConfiguration.java @@ -39,8 +39,9 @@ import net.devh.boot.grpc.client.channelfactory.GrpcChannelConfigurer; import net.devh.boot.grpc.client.channelfactory.GrpcChannelFactory; import net.devh.boot.grpc.client.channelfactory.InProcessChannelFactory; -import net.devh.boot.grpc.client.channelfactory.InProcessOrAlternativeChannelFactory; import net.devh.boot.grpc.client.channelfactory.NettyChannelFactory; +import net.devh.boot.grpc.client.channelfactory.NullChannelFactory; +import net.devh.boot.grpc.client.channelfactory.SchemaAwareChannelFactory; import net.devh.boot.grpc.client.channelfactory.ShadedNettyChannelFactory; import net.devh.boot.grpc.client.config.GrpcChannelsProperties; import net.devh.boot.grpc.client.inject.GrpcClientBeanPostProcessor; @@ -139,6 +140,7 @@ List defaultChannelConfigurers() { } // First try the shaded netty channel factory + @SuppressWarnings("resource") @ConditionalOnMissingBean(GrpcChannelFactory.class) @ConditionalOnClass(name = {"io.grpc.netty.shaded.io.netty.channel.Channel", "io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder"}) @@ -152,12 +154,15 @@ GrpcChannelFactory shadedNettyGrpcChannelFactory( log.info("Detected grpc-netty-shaded: Creating ShadedNettyChannelFactory + InProcessChannelFactory"); final ShadedNettyChannelFactory channelFactory = new ShadedNettyChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers); - final InProcessChannelFactory inProcessChannelFactory = + final InProcessChannelFactory inProcess = new InProcessChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers); - return new InProcessOrAlternativeChannelFactory(properties, inProcessChannelFactory, channelFactory); + return new SchemaAwareChannelFactory(properties, channelFactory) + .put(InProcessChannelFactory.SCHEME, inProcess) + .put(NullChannelFactory.SCHEME, new NullChannelFactory()); } // Then try the normal netty channel factory + @SuppressWarnings("resource") @ConditionalOnMissingBean(GrpcChannelFactory.class) @ConditionalOnClass(name = {"io.netty.channel.Channel", "io.grpc.netty.NettyChannelBuilder"}) @Bean @@ -170,9 +175,11 @@ GrpcChannelFactory nettyGrpcChannelFactory( log.info("Detected grpc-netty: Creating NettyChannelFactory + InProcessChannelFactory"); final NettyChannelFactory channelFactory = new NettyChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers); - final InProcessChannelFactory inProcessChannelFactory = + final InProcessChannelFactory inProcess = new InProcessChannelFactory(properties, globalClientInterceptorRegistry, channelConfigurers); - return new InProcessOrAlternativeChannelFactory(properties, inProcessChannelFactory, channelFactory); + return new SchemaAwareChannelFactory(properties, channelFactory) + .put(InProcessChannelFactory.SCHEME, inProcess) + .put(NullChannelFactory.SCHEME, new NullChannelFactory()); } // Finally try the in process channel factory diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/GrpcChannelFactory.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/GrpcChannelFactory.java index 2958c3d38..55702ea2c 100644 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/GrpcChannelFactory.java +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/GrpcChannelFactory.java @@ -45,7 +45,8 @@ public interface GrpcChannelFactory extends AutoCloseable { *

* * @param name The name of the service. - * @return The newly created channel for the given service. + * @return The newly created channel for the given service. Might return null if the channel was intentionally + * skipped. */ default Channel createChannel(final String name) { return createChannel(name, Collections.emptyList()); @@ -66,7 +67,8 @@ default Channel createChannel(final String name) { * * @param name The name of the service. * @param interceptors A list of additional client interceptors that should be added to the channel. - * @return The newly created channel for the given service. + * @return The newly created channel for the given service. Might return null if the channel was intentionally + * skipped. */ default Channel createChannel(final String name, final List interceptors) { return createChannel(name, interceptors, false); @@ -88,7 +90,8 @@ default Channel createChannel(final String name, final List i * @param name The name of the service. * @param interceptors A list of additional client interceptors that should be added to the channel. * @param sortInterceptors Whether the interceptors (both global and custom) should be sorted before being applied. - * @return The newly created channel for the given service. + * @return The newly created channel for the given service. Might return null if the channel was intentionally + * skipped. */ Channel createChannel(String name, List interceptors, boolean sortInterceptors); diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessChannelFactory.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessChannelFactory.java index 63d27eec9..962c88653 100644 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessChannelFactory.java +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessChannelFactory.java @@ -17,6 +17,7 @@ package net.devh.boot.grpc.client.channelfactory; +import java.net.URI; import java.util.Collections; import java.util.List; @@ -37,14 +38,21 @@ @Slf4j public class InProcessChannelFactory extends AbstractChannelFactory { + /** + * The scheme of this factory: {@value #SCHEME}. + */ + public static final String SCHEME = "in-process"; + /** * Creates a new InProcessChannelFactory with the given properties. * * @param properties The properties for the channels to create. * @param globalClientInterceptorRegistry The interceptor registry to use. */ - public InProcessChannelFactory(final GrpcChannelsProperties properties, + public InProcessChannelFactory( + final GrpcChannelsProperties properties, final GlobalClientInterceptorRegistry globalClientInterceptorRegistry) { + this(properties, globalClientInterceptorRegistry, Collections.emptyList()); } @@ -55,16 +63,20 @@ public InProcessChannelFactory(final GrpcChannelsProperties properties, * @param globalClientInterceptorRegistry The interceptor registry to use. * @param channelConfigurers The channel configurers to use. Can be empty. */ - public InProcessChannelFactory(final GrpcChannelsProperties properties, + public InProcessChannelFactory( + final GrpcChannelsProperties properties, final GlobalClientInterceptorRegistry globalClientInterceptorRegistry, final List channelConfigurers) { + super(properties, globalClientInterceptorRegistry, channelConfigurers); } @Override protected InProcessChannelBuilder newChannelBuilder(final String name) { - log.debug("Creating new channel: {}", name); - return InProcessChannelBuilder.forName(name); + final URI address = getPropertiesFor(name).getAddress(); + final String target = address == null ? name : address.getSchemeSpecificPart(); + log.debug("Creating new channel: {}", target); + return InProcessChannelBuilder.forName(target); } @Override diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessOrAlternativeChannelFactory.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessOrAlternativeChannelFactory.java deleted file mode 100644 index 0feb7e225..000000000 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/InProcessOrAlternativeChannelFactory.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2016-2020 Michael Zhang - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated - * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the - * Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -package net.devh.boot.grpc.client.channelfactory; - -import static java.util.Objects.requireNonNull; - -import java.net.URI; -import java.util.List; -import java.util.Map; - -import com.google.common.collect.ImmutableMap; - -import io.grpc.Channel; -import io.grpc.ClientInterceptor; -import io.grpc.ConnectivityState; -import net.devh.boot.grpc.client.config.GrpcChannelsProperties; - -/** - * This channel factory is a switch between the {@link InProcessChannelFactory} and an alternative implementation. All - * channels that are configured with the {@code in-process} scheme will be handled by the in-process-channel-factory, - * the other channels will be handled by the alternative implementation. - * - *

- * The following examples show how the configured address will be mapped to an actual channel: - *

- * - *
    - *
  • in-process:foobar -> will use the foobar in-process-channel.
  • - *
  • in-process:foo/bar -> will use the foo/bar in-process-channel.
  • - *
  • static://127.0.0.1 -> will be handled by the alternative grpc channel factory.
  • - *
- * - *

- * Using this class does not incur any additional performance or resource costs, as the actual channels (in-process or - * other) are only created on demand. - *

- */ -public class InProcessOrAlternativeChannelFactory implements GrpcChannelFactory { - - private static final String IN_PROCESS_SCHEME = "in-process"; - - private final GrpcChannelsProperties properties; - private final InProcessChannelFactory inProcessChannelFactory; - private final GrpcChannelFactory alternativeChannelFactory; - - /** - * Creates a new InProcessOrAlternativeChannelFactory with the given properties and channel factories. - * - * @param properties The properties used to resolved the target scheme - * @param inProcessChannelFactory The in process channel factory implementation to use. - * @param alternativeChannelFactory The alternative channel factory implementation to use. - */ - public InProcessOrAlternativeChannelFactory(final GrpcChannelsProperties properties, - final InProcessChannelFactory inProcessChannelFactory, final GrpcChannelFactory alternativeChannelFactory) { - this.properties = requireNonNull(properties, "properties"); - this.inProcessChannelFactory = requireNonNull(inProcessChannelFactory, "inProcessChannelFactory"); - this.alternativeChannelFactory = requireNonNull(alternativeChannelFactory, "alternativeChannelFactory"); - } - - @Override - public Channel createChannel(final String name, final List interceptors, - boolean sortInterceptors) { - final URI address = this.properties.getChannel(name).getAddress(); - if (address != null && IN_PROCESS_SCHEME.equals(address.getScheme())) { - return this.inProcessChannelFactory.createChannel(address.getSchemeSpecificPart(), interceptors, - sortInterceptors); - } - return this.alternativeChannelFactory.createChannel(name, interceptors, sortInterceptors); - } - - @Override - public Map getConnectivityState() { - return ImmutableMap.builder() - .putAll(inProcessChannelFactory.getConnectivityState()) - .putAll(alternativeChannelFactory.getConnectivityState()) - .build(); - } - - @Override - public void close() { - try { - this.inProcessChannelFactory.close(); - } finally { - this.alternativeChannelFactory.close(); - } - } - -} diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/NullChannelFactory.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/NullChannelFactory.java new file mode 100644 index 000000000..69ca0acfe --- /dev/null +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/NullChannelFactory.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.client.channelfactory; + +import java.util.List; + +import io.grpc.Channel; +import io.grpc.ClientInterceptor; + +/** + * An dummy channel factory that always returns null. Useful for skipping specific channels during tests/profiles. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +public final class NullChannelFactory implements GrpcChannelFactory { + + /** + * The scheme of this factory: {@value #SCHEME}. + */ + public static final String SCHEME = "null"; + + @Override + public Channel createChannel( + final String name, + final List interceptors, + final boolean sortInterceptors) { + return null; + } + + @Override + public void close() { + // Nothing to do + } + +} diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/SchemaAwareChannelFactory.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/SchemaAwareChannelFactory.java new file mode 100644 index 000000000..561c92f91 --- /dev/null +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/channelfactory/SchemaAwareChannelFactory.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.client.channelfactory; + +import java.net.URI; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import io.grpc.Channel; +import io.grpc.ClientInterceptor; +import net.devh.boot.grpc.client.config.GrpcChannelsProperties; + +/** + * Creates a schema aware channel factory. The actual {@link GrpcChannelFactory} is chosen based on the scheme of the + * address associated to the requested channel name. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +public class SchemaAwareChannelFactory implements GrpcChannelFactory { + + private final GrpcChannelsProperties properties; + private final Map factories; + private final GrpcChannelFactory fallback; + + /** + * Creates a new SchemaAwareChannelFactory. + * + * @param properties The properties to lookup the addresses. + * @param fallback The fallback factory to use if the scheme does not match a specific factory. + */ + public SchemaAwareChannelFactory( + final GrpcChannelsProperties properties, + final GrpcChannelFactory fallback) { + + this(properties, new HashMap<>(), fallback); + } + + /** + * Creates a new SchemaAwareChannelFactory. + * + * @param properties The properties to lookup the addresses. + * @param factories The factories by their associated scheme. + * @param fallback The fallback factory to use if the scheme does not match a specific factory. + */ + public SchemaAwareChannelFactory( + final GrpcChannelsProperties properties, + final Map factories, + final GrpcChannelFactory fallback) { + + this.properties = properties; + this.factories = new HashMap<>(factories); + this.fallback = fallback; + } + + @Override + public Channel createChannel( + final String name, + final List interceptors, + final boolean sortInterceptors) { + + final URI address = this.properties.getChannel(name).getAddress(); + final String scheme = address == null ? null : address.getScheme(); + return this.factories.getOrDefault(scheme, this.fallback) + .createChannel(name, interceptors, sortInterceptors); + } + + public SchemaAwareChannelFactory put(final String scheme, final GrpcChannelFactory factory) { + this.factories.put(scheme, factory); + return this; + } + + @Override + public void close() { + for (final GrpcChannelFactory factory : this.factories.values()) { + factory.close(); + } + this.fallback.close(); + } + +} diff --git a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java index b1b1ad190..c1c12eef2 100644 --- a/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java +++ b/grpc-client-spring-boot-autoconfigure/src/main/java/net/devh/boot/grpc/client/inject/GrpcClientBeanPostProcessor.java @@ -119,7 +119,7 @@ protected T processInjectionPoint(final Member injectionTarget, final Class< try { channel = getChannelFactory().createChannel(name, interceptors, annotation.sortInterceptors()); if (channel == null) { - throw new IllegalStateException("Channel factory created a null channel for " + name); + return null; } } catch (final RuntimeException e) { throw new IllegalStateException("Failed to create channel: " + name, e); diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientInjectionTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/AbstractGrpcClientInjectionTest.java similarity index 68% rename from tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientInjectionTest.java rename to tests/src/test/java/net/devh/boot/grpc/test/inject/AbstractGrpcClientInjectionTest.java index a4a587fbf..b0e7e45f5 100644 --- a/tests/src/test/java/net/devh/boot/grpc/test/inject/GrpcClientInjectionTest.java +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/AbstractGrpcClientInjectionTest.java @@ -22,24 +22,18 @@ import javax.annotation.PostConstruct; import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.test.annotation.DirtiesContext; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import io.grpc.Channel; import io.grpc.stub.AbstractStub; import net.devh.boot.grpc.client.inject.GrpcClient; import net.devh.boot.grpc.client.stubfactory.StandardJavaGrpcStubFactory; import net.devh.boot.grpc.client.stubfactory.StubFactory; -import net.devh.boot.grpc.test.config.BaseAutoConfiguration; -import net.devh.boot.grpc.test.config.InProcessConfiguration; -import net.devh.boot.grpc.test.config.ServiceConfiguration; import net.devh.boot.grpc.test.inject.CustomGrpc.ConstructorAccessibleStub; import net.devh.boot.grpc.test.inject.CustomGrpc.CustomAccessibleStub; import net.devh.boot.grpc.test.inject.CustomGrpc.FactoryMethodAccessibleStub; -import net.devh.boot.grpc.test.inject.GrpcClientInjectionTest.TestConfig; import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceBlockingStub; import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceFutureStub; import net.devh.boot.grpc.test.proto.TestServiceGrpc.TestServiceStub; @@ -49,11 +43,8 @@ * * @author Daniel Theuke (daniel.theuke@heuboe.de) */ -@SpringBootTest -@SpringJUnitConfig(classes = {TestConfig.class, InProcessConfiguration.class, ServiceConfiguration.class, - BaseAutoConfiguration.class}) @DirtiesContext -class GrpcClientInjectionTest { +abstract class AbstractGrpcClientInjectionTest { @GrpcClient("test") Channel channel; @@ -81,75 +72,79 @@ class GrpcClientInjectionTest { @PostConstruct public void init() { // Test injection - assertNotNull(this.channel, "channel"); - assertNotNull(this.stub, "stub"); - assertNotNull(this.blockingStub, "blockingStub"); - assertNotNull(this.futureStub, "futureStub"); - assertNotNull(this.constructorStub, "constructorStub"); - assertNotNull(this.factoryMethodStub, "factoryMethodStub"); - assertNotNull(this.customStub, "customStub"); + assertValid(this.channel, "channel"); + assertValid(this.stub, "stub"); + assertValid(this.blockingStub, "blockingStub"); + assertValid(this.futureStub, "futureStub"); + assertValid(this.constructorStub, "constructorStub"); + assertValid(this.factoryMethodStub, "factoryMethodStub"); + assertValid(this.customStub, "customStub"); } @GrpcClient("test") void inject(final Channel channel) { - assertNotNull(channel, "channel"); + assertValid(channel, "channel"); this.channelSetted = channel; } @GrpcClient("test") void inject(final TestServiceStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.stubSetted = stub; } @GrpcClient("test") void inject(final TestServiceBlockingStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.blockingStubSetted = stub; } @GrpcClient("test") void inject(final TestServiceFutureStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.futureStubSetted = stub; } @GrpcClient("test") void inject(final ConstructorAccessibleStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.constructorStubSetted = stub; } @GrpcClient("test") void inject(final FactoryMethodAccessibleStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.factoryMethodStubSetted = stub; } @GrpcClient("test") void inject(final CustomAccessibleStub stub) { - assertNotNull(stub, "stub"); + assertValid(stub, "stub"); this.customStubSetted = stub; } @Test void testAllSet() { // Field injection - assertNotNull(this.channel, "channel"); - assertNotNull(this.stub, "stub"); - assertNotNull(this.blockingStub, "blockingStub"); - assertNotNull(this.futureStub, "futureStub"); - assertNotNull(this.constructorStub, "constructorStub"); - assertNotNull(this.factoryMethodStub, "factoryMethodStub"); - assertNotNull(this.customStub, "customStub"); + assertValid(this.channel, "channel"); + assertValid(this.stub, "stub"); + assertValid(this.blockingStub, "blockingStub"); + assertValid(this.futureStub, "futureStub"); + assertValid(this.constructorStub, "constructorStub"); + assertValid(this.factoryMethodStub, "factoryMethodStub"); + assertValid(this.customStub, "customStub"); // Setter injection - assertNotNull(this.channelSetted, "channelSetted"); - assertNotNull(this.stubSetted, "stubSetted"); - assertNotNull(this.blockingStubSetted, "blockingStubSetted"); - assertNotNull(this.futureStubSetted, "futureStubSetted"); - assertNotNull(this.constructorStubSetted, "constructorStubSetted"); - assertNotNull(this.factoryMethodStubSetted, "factoryMethodStubSetted"); - assertNotNull(this.customStubSetted, "customStubSetted"); + assertValid(this.channelSetted, "channelSetted"); + assertValid(this.stubSetted, "stubSetted"); + assertValid(this.blockingStubSetted, "blockingStubSetted"); + assertValid(this.futureStubSetted, "futureStubSetted"); + assertValid(this.constructorStubSetted, "constructorStubSetted"); + assertValid(this.factoryMethodStubSetted, "factoryMethodStubSetted"); + assertValid(this.customStubSetted, "customStubSetted"); + } + + protected void assertValid(final Object actual, final String message) { + assertNotNull(actual, message); } @TestConfiguration diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultInProcessGrpcClientInjectionTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultInProcessGrpcClientInjectionTest.java new file mode 100644 index 000000000..b4542ac99 --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultInProcessGrpcClientInjectionTest.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.test.inject; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +import net.devh.boot.grpc.test.config.BaseAutoConfiguration; +import net.devh.boot.grpc.test.config.ServiceConfiguration; + +/** + * A test checking that the client injection works. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +@SpringBootTest(classes = { + DefaultInProcessGrpcClientInjectionTest.TestConfig.class, + ServiceConfiguration.class, + BaseAutoConfiguration.class, +}, properties = { + "grpc.server.in-process-name=test", + "grpc.server.port=-1", + "grpc.client.test.address=in-process:test", +}) +@DirtiesContext +class DefaultInProcessGrpcClientInjectionTest extends AbstractGrpcClientInjectionTest { +} diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNettyGrpcClientInjectionTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNettyGrpcClientInjectionTest.java new file mode 100644 index 000000000..a0b63e06b --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNettyGrpcClientInjectionTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.test.inject; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +import net.devh.boot.grpc.test.config.BaseAutoConfiguration; +import net.devh.boot.grpc.test.config.ServiceConfiguration; + +/** + * A test checking that the client injection works. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +@SpringBootTest(classes = { + DefaultNettyGrpcClientInjectionTest.TestConfig.class, + ServiceConfiguration.class, + BaseAutoConfiguration.class, +}, properties = { + "grpc.client.test.address=dns:/localhost", +}) +@DirtiesContext +class DefaultNettyGrpcClientInjectionTest extends AbstractGrpcClientInjectionTest { +} diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNullGrpcClientInjectionTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNullGrpcClientInjectionTest.java new file mode 100644 index 000000000..e46eb3258 --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/DefaultNullGrpcClientInjectionTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.test.inject; + +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +import net.devh.boot.grpc.test.config.BaseAutoConfiguration; +import net.devh.boot.grpc.test.config.ServiceConfiguration; + +/** + * A test checking that the client injection works. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +@SpringBootTest(classes = { + DefaultNullGrpcClientInjectionTest.TestConfig.class, + ServiceConfiguration.class, + BaseAutoConfiguration.class, +}, properties = { + "grpc.server.port=-1", + "grpc.client.test.address=null:/", +}) +@DirtiesContext +class DefaultNullGrpcClientInjectionTest extends AbstractGrpcClientInjectionTest { + + @Override + protected void assertValid(final Object actual, final String message) { + assertNull(actual, message); + } + +} diff --git a/tests/src/test/java/net/devh/boot/grpc/test/inject/InProcessClientInjectionTest.java b/tests/src/test/java/net/devh/boot/grpc/test/inject/InProcessClientInjectionTest.java new file mode 100644 index 000000000..c5c3ea136 --- /dev/null +++ b/tests/src/test/java/net/devh/boot/grpc/test/inject/InProcessClientInjectionTest.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016-2020 Michael Zhang + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated + * documentation files (the "Software"), to deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package net.devh.boot.grpc.test.inject; + +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.annotation.DirtiesContext; + +import net.devh.boot.grpc.test.config.BaseAutoConfiguration; +import net.devh.boot.grpc.test.config.InProcessConfiguration; +import net.devh.boot.grpc.test.config.ServiceConfiguration; + +/** + * A test checking that the client injection works. + * + * @author Daniel Theuke (daniel.theuke@heuboe.de) + */ +@SpringBootTest(classes = { + DefaultNettyGrpcClientInjectionTest.TestConfig.class, + InProcessConfiguration.class, + ServiceConfiguration.class, + BaseAutoConfiguration.class, +}) +@DirtiesContext +class InProcessClientInjectionTest extends AbstractGrpcClientInjectionTest { + +}