diff --git a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java index 677c243adb9e0..e0864269dea70 100644 --- a/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java +++ b/extensions/grpc/deployment/src/main/java/io/quarkus/grpc/deployment/GrpcServerProcessor.java @@ -148,17 +148,18 @@ void processGeneratedBeans(CombinedIndexBuildItem index, BuildProducer examples.GreeterGrpc.GreeterImplBase DotName implBase = DotName.createSimple(mutinyImplBaseName.replace(MutinyGrpcGenerator.CLASS_PREFIX, "")); if (!index.getIndex().getAllKnownSubclasses(implBase).isEmpty()) { - // Some class extends the impl base - continue; + // Some class already extends the impl base + throw new IllegalStateException("Duplicated gRPC service: " + implBase); } // Finally, exclude some packages boolean excluded = false; @@ -235,6 +236,7 @@ void discoverBindableServices(BuildProducer bindables, if (Modifier.isAbstract(service.flags())) { continue; } + BindableServiceBuildItem item = new BindableServiceBuildItem(service.name()); Set blockingMethods = gatherBlockingOrVirtualMethodNames(service, index, false); Set virtualMethods = gatherBlockingOrVirtualMethodNames(service, index, true); diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/Duplicate2ServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/Duplicate2ServiceTest.java new file mode 100644 index 0000000000000..f745b9746e324 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/Duplicate2ServiceTest.java @@ -0,0 +1,35 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.Poke2Service; +import io.quarkus.grpc.server.dups.PokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 2 same implBase services +@Disabled("Currently not detected at build time") +public class Duplicate2ServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(Poke2Service.class, PokeService.class) + .addPackage(Poke.class.getPackage())) + .assertException(t -> { + Assertions.assertTrue(t.getMessage().contains("Duplicated gRPC service")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateBeansServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateBeansServiceTest.java new file mode 100644 index 0000000000000..3161276c8f834 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateBeansServiceTest.java @@ -0,0 +1,34 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.MutinyPoke2Service; +import io.quarkus.grpc.server.dups.MutinyPokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 2 same beans services +public class DuplicateBeansServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MutinyPokeService.class, MutinyPoke2Service.class) + .addPackage(Poke.class.getPackage())) + .assertException(t -> { + // fails with CDI / Arc + Assertions.assertTrue(t.getMessage().contains("Ambiguous dependencies")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java new file mode 100644 index 0000000000000..06af51939b9e7 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/DuplicateServiceTest.java @@ -0,0 +1,33 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.MutinyPokeService; +import io.quarkus.grpc.server.dups.PokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 1 implBase + 1 bean +public class DuplicateServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MutinyPokeService.class, PokeService.class) + .addPackage(Poke.class.getPackage())) + .assertException(t -> { + Assertions.assertTrue(t.getMessage().contains("Duplicated gRPC service")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicate2ServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicate2ServiceTest.java new file mode 100644 index 0000000000000..da0d500c67c60 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicate2ServiceTest.java @@ -0,0 +1,35 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.MPoke2Service; +import io.quarkus.grpc.server.dups.MPokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 2 same mutinyImplBase services +@Disabled("Currently not detected at build time") +public class MDuplicate2ServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MPoke2Service.class, MPokeService.class) + .addPackage(Poke.class.getPackage())) + .assertException(t -> { + Assertions.assertTrue(t.getMessage().contains("Duplicated gRPC service")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicateServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicateServiceTest.java new file mode 100644 index 0000000000000..f978a8708732a --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/MDuplicateServiceTest.java @@ -0,0 +1,33 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.MPokeService; +import io.quarkus.grpc.server.dups.MutinyPokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 1 mutinyImplBase + 1 bean +public class MDuplicateServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MutinyPokeService.class, MPokeService.class) + .addPackage(Poke.class.getPackage())) + .assertException(t -> { + Assertions.assertTrue(t.getMessage().contains("Duplicated gRPC service")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/VertxDuplicateServiceTest.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/VertxDuplicateServiceTest.java new file mode 100644 index 0000000000000..2ce824c22733f --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/VertxDuplicateServiceTest.java @@ -0,0 +1,34 @@ +package io.quarkus.grpc.server; + +import static org.junit.jupiter.api.Assertions.fail; + +import org.jboss.shrinkwrap.api.ShrinkWrap; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import io.grpc.examples.dups.Poke; +import io.quarkus.grpc.server.dups.MutinyPokeService; +import io.quarkus.grpc.server.dups.PokeService; +import io.quarkus.test.QuarkusUnitTest; + +// 1 implBase + 1 bean -- with Vert.x based gRPC +public class VertxDuplicateServiceTest { + + @RegisterExtension + static final QuarkusUnitTest unitTest = new QuarkusUnitTest() + .setArchiveProducer(() -> ShrinkWrap.create(JavaArchive.class) + .addClasses(MutinyPokeService.class, PokeService.class) + .addPackage(Poke.class.getPackage())) + .overrideConfigKey("quarkus.grpc.server.use-separate-server", "false") + .assertException(t -> { + Assertions.assertTrue(t.getMessage().contains("Duplicated gRPC service")); + }); + + @Test + void testDuplicateService() { + fail("Should not be called"); + } + +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPoke2Service.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPoke2Service.java new file mode 100644 index 0000000000000..b3593bafc996f --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPoke2Service.java @@ -0,0 +1,15 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.MutinyPokeGrpc; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.quarkus.grpc.GrpcService; +import io.smallrye.mutiny.Uni; + +@GrpcService +public class MPoke2Service extends MutinyPokeGrpc.PokeImplBase { + @Override + public Uni poke(PokeRequest request) { + return super.poke(request); + } +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPokeService.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPokeService.java new file mode 100644 index 0000000000000..5538631e5628a --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MPokeService.java @@ -0,0 +1,15 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.MutinyPokeGrpc; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.quarkus.grpc.GrpcService; +import io.smallrye.mutiny.Uni; + +@GrpcService +public class MPokeService extends MutinyPokeGrpc.PokeImplBase { + @Override + public Uni poke(PokeRequest request) { + return super.poke(request); + } +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPoke2Service.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPoke2Service.java new file mode 100644 index 0000000000000..44b9cd5d1dcf0 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPoke2Service.java @@ -0,0 +1,15 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.Poke; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.quarkus.grpc.GrpcService; +import io.smallrye.mutiny.Uni; + +@GrpcService +public class MutinyPoke2Service implements Poke { + @Override + public Uni poke(PokeRequest request) { + return null; + } +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPokeService.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPokeService.java new file mode 100644 index 0000000000000..09b17d913dee4 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/MutinyPokeService.java @@ -0,0 +1,15 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.Poke; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.quarkus.grpc.GrpcService; +import io.smallrye.mutiny.Uni; + +@GrpcService +public class MutinyPokeService implements Poke { + @Override + public Uni poke(PokeRequest request) { + return null; + } +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/Poke2Service.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/Poke2Service.java new file mode 100644 index 0000000000000..b5ceb9af877c5 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/Poke2Service.java @@ -0,0 +1,14 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.PokeGrpc; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.grpc.stub.StreamObserver; +import io.quarkus.grpc.GrpcService; + +@GrpcService +public class Poke2Service extends PokeGrpc.PokeImplBase { + @Override + public void poke(PokeRequest request, StreamObserver responseObserver) { + } +} diff --git a/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/PokeService.java b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/PokeService.java new file mode 100644 index 0000000000000..aea1c0563c0c6 --- /dev/null +++ b/extensions/grpc/deployment/src/test/java/io/quarkus/grpc/server/dups/PokeService.java @@ -0,0 +1,14 @@ +package io.quarkus.grpc.server.dups; + +import io.grpc.examples.dups.PokeGrpc; +import io.grpc.examples.dups.PokeReply; +import io.grpc.examples.dups.PokeRequest; +import io.grpc.stub.StreamObserver; +import io.quarkus.grpc.GrpcService; + +@GrpcService +public class PokeService extends PokeGrpc.PokeImplBase { + @Override + public void poke(PokeRequest request, StreamObserver responseObserver) { + } +} diff --git a/extensions/grpc/deployment/src/test/proto/dups.proto b/extensions/grpc/deployment/src/test/proto/dups.proto new file mode 100644 index 0000000000000..df57125fd3183 --- /dev/null +++ b/extensions/grpc/deployment/src/test/proto/dups.proto @@ -0,0 +1,20 @@ +syntax = "proto3"; + +option java_multiple_files = true; +option java_package = "io.grpc.examples.dups"; +option java_outer_classname = "DupsFooProto"; +option objc_class_prefix = "DF"; + +package dups; + +service Poke { + rpc poke (PokeRequest) returns (PokeReply) {} +} + +message PokeRequest { + string name = 1; +} + +message PokeReply { + string message = 1; +} diff --git a/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1.java b/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1.java index 1c668087de500..a685bcc6a96b8 100644 --- a/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1.java +++ b/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1.java @@ -28,8 +28,12 @@ public class ReflectionServiceV1 extends MutinyServerReflectionGrpc.ServerReflec private final GrpcServerIndex index; + public ReflectionServiceV1(GrpcServerIndex index) { + this.index = index; + } + public ReflectionServiceV1(List definitions) { - index = new GrpcServerIndex(definitions); + this(new GrpcServerIndex(definitions)); } @Override diff --git a/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1alpha.java b/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1alpha.java index a590fdfe2a95a..436a747a384b4 100644 --- a/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1alpha.java +++ b/extensions/grpc/reflection/src/main/java/io/quarkus/grpc/reflection/service/ReflectionServiceV1alpha.java @@ -21,8 +21,12 @@ public class ReflectionServiceV1alpha extends MutinyServerReflectionGrpc.ServerR private final GrpcServerIndex index; + public ReflectionServiceV1alpha(GrpcServerIndex index) { + this.index = index; + } + public ReflectionServiceV1alpha(List definitions) { - index = new GrpcServerIndex(definitions); + this(new GrpcServerIndex(definitions)); } @Override diff --git a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java index 848a2671c0702..421c2ca571fc5 100644 --- a/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java +++ b/extensions/grpc/runtime/src/main/java/io/quarkus/grpc/runtime/GrpcServerRecorder.java @@ -177,7 +177,6 @@ private void buildGrpcServer(Vertx vertx, GrpcServerConfiguration configuration, } boolean reflectionServiceEnabled = configuration.enableReflectionService || launchMode == LaunchMode.DEVELOPMENT; - if (reflectionServiceEnabled) { LOGGER.info("Registering gRPC reflection service"); ReflectionServiceV1 reflectionServiceV1 = new ReflectionServiceV1(definitions); @@ -261,7 +260,9 @@ private void prodStart(GrpcContainer grpcContainer, Vertx vertx, GrpcServerConfi } catch (TimeoutException e) { LOGGER.error("Unable to start the gRPC server, still not listening after 1 minute"); } catch (ExecutionException e) { - LOGGER.error("Unable to start the gRPC server", e.getCause()); + Throwable cause = e.getCause(); + LOGGER.error("Unable to start the gRPC server", cause); + throw new RuntimeException(cause); } } @@ -325,11 +326,11 @@ private void devModeStart(GrpcContainer grpcContainer, Vertx vertx, GrpcServerCo try { future.get(1, TimeUnit.MINUTES); } catch (TimeoutException e) { - LOGGER.error("Failed to start grpc server in time", e); + LOGGER.error("Failed to start gRPC server in time", e); } catch (ExecutionException e) { - throw new RuntimeException("grpc server start failed", e); + throw new RuntimeException("Unable to start the gRPC server", e); } catch (InterruptedException e) { - LOGGER.warn("Waiting for grpc server start interrupted", e); + LOGGER.warn("Waiting for gRPC server start interrupted", e); Thread.currentThread().interrupt(); } @@ -530,7 +531,6 @@ private Map.Entry buildServer(Vertx vertx, GrpcServerConfigurat applyTransportSecurityConfig(configuration, builder); - boolean reflectionServiceEnabled = configuration.enableReflectionService || launchMode == LaunchMode.DEVELOPMENT; List toBeRegistered = collectServiceDefinitions(grpcContainer.getServices()); List definitions = new ArrayList<>(); @@ -547,6 +547,7 @@ private Map.Entry buildServer(Vertx vertx, GrpcServerConfigurat definitions.add(service.definition); } + boolean reflectionServiceEnabled = configuration.enableReflectionService || launchMode == LaunchMode.DEVELOPMENT; if (reflectionServiceEnabled) { LOGGER.info("Registering gRPC reflection service"); builder.addService(ServerInterceptors.intercept(new ReflectionServiceV1(definitions), globalInterceptors));