sortedInterceptors) {
+ server = null;
+ }
+
+ public static void shutdown() {
+ shutdown(server);
+ server = null;
+ }
+
+ public static void shutdown(Server current) {
+ if (current != null) {
+ current.shutdownNow();
+ }
+ }
+}
diff --git a/extensions/grpc/xds/src/main/resources/META-INF/services/io.quarkus.grpc.spi.GrpcBuilderProvider b/extensions/grpc/xds/src/main/resources/META-INF/services/io.quarkus.grpc.spi.GrpcBuilderProvider
new file mode 100644
index 0000000000000..d54d69a8d823e
--- /dev/null
+++ b/extensions/grpc/xds/src/main/resources/META-INF/services/io.quarkus.grpc.spi.GrpcBuilderProvider
@@ -0,0 +1 @@
+io.quarkus.grpc.xds.XdsGrpcServerBuilderProvider
\ No newline at end of file
diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/ClientExceptionMapperHandler.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/ClientExceptionMapperHandler.java
index 3e498c2629e67..53590911221eb 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/ClientExceptionMapperHandler.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/ClientExceptionMapperHandler.java
@@ -1,6 +1,8 @@
package io.quarkus.rest.client.reactive.deployment;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.LinkedHashMap;
import javax.ws.rs.Priorities;
import javax.ws.rs.core.Response;
@@ -12,12 +14,15 @@
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.MethodInfo;
import org.jboss.jandex.Type;
+import org.jboss.resteasy.reactive.client.impl.RestClientRequestContext;
+import org.jboss.resteasy.reactive.common.processor.ResteasyReactiveDotNames;
import io.quarkus.gizmo.ClassCreator;
import io.quarkus.gizmo.ClassOutput;
import io.quarkus.gizmo.MethodCreator;
import io.quarkus.gizmo.MethodDescriptor;
import io.quarkus.gizmo.ResultHandle;
+import io.quarkus.rest.client.reactive.runtime.ResteasyReactiveResponseExceptionMapper;
import io.quarkus.runtime.util.HashUtil;
/**
@@ -26,6 +31,10 @@
*/
class ClientExceptionMapperHandler {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+ private static final ResultHandle[] EMPTY_RESULT_HANDLES_ARRAY = new ResultHandle[0];
+ private static final MethodDescriptor GET_INVOKED_METHOD =
+ MethodDescriptor.ofMethod(RestClientRequestContext.class, "getInvokedMethod", Method.class);
private final ClassOutput classOutput;
ClientExceptionMapperHandler(ClassOutput classOutput) {
@@ -37,8 +46,8 @@ class ClientExceptionMapperHandler {
*
*
* {@code
- * public class SomeService_map_ResponseExceptionMapper_a8fb70beeef2a54b80151484d109618eed381626 implements ResponseExceptionMapper {
- * public Throwable toThrowable(Response var1) {
+ * public class SomeService_map_ResponseExceptionMapper_a8fb70beeef2a54b80151484d109618eed381626 implements ResteasyReactiveResponseExceptionMapper {
+ * public Throwable toThrowable(Response var1, RestClientRequestContext var2) {
* // simply call the static method of interface
* return SomeService.map(var1);
* }
@@ -97,15 +106,32 @@ Result generateResponseExceptionMapper(AnnotationInstance instance) {
String generatedClassName = restClientInterfaceClassInfo.name().toString() + "_" + targetMethod.name() + "_"
+ "ResponseExceptionMapper" + "_" + HashUtil.sha1(sigBuilder.toString());
try (ClassCreator cc = ClassCreator.builder().classOutput(classOutput).className(generatedClassName)
- .interfaces(ResponseExceptionMapper.class).build()) {
- MethodCreator toThrowable = cc.getMethodCreator("toThrowable", Throwable.class, Response.class);
+ .interfaces(ResteasyReactiveResponseExceptionMapper.class).build()) {
+ MethodCreator toThrowable = cc.getMethodCreator("toThrowable", Throwable.class, Response.class,
+ RestClientRequestContext.class);
+ LinkedHashMap targetMethodParams = new LinkedHashMap<>();
+ for (Type paramType : targetMethod.parameterTypes()) {
+ ResultHandle targetMethodParamHandle;
+ if (paramType.name().equals(ResteasyReactiveDotNames.RESPONSE)) {
+ targetMethodParamHandle = toThrowable.getMethodParam(0);
+ } else if (paramType.name().equals(DotNames.METHOD)) {
+ targetMethodParamHandle = toThrowable.invokeVirtualMethod(GET_INVOKED_METHOD, toThrowable.getMethodParam(1));
+ } else {
+ String message = DotNames.CLIENT_EXCEPTION_MAPPER + " can only take parameters of type '" + ResteasyReactiveDotNames.RESPONSE + "' or '" + DotNames.METHOD + "'"
+ + " Offending instance is '" + targetMethod.declaringClass().name().toString() + "#"
+ + targetMethod.name() + "'";
+ throw new IllegalStateException(message);
+ }
+ targetMethodParams.put(paramType.name().toString(), targetMethodParamHandle);
+ }
+
ResultHandle resultHandle = toThrowable.invokeStaticInterfaceMethod(
MethodDescriptor.ofMethod(
restClientInterfaceClassInfo.name().toString(),
targetMethod.name(),
targetMethod.returnType().name().toString(),
- targetMethod.parameterType(0).name().toString()),
- toThrowable.getMethodParam(0));
+ targetMethodParams.keySet().toArray(EMPTY_STRING_ARRAY)),
+ targetMethodParams.values().toArray(EMPTY_RESULT_HANDLES_ARRAY));
toThrowable.returnValue(resultHandle);
if (priority != Priorities.USER) {
diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/DotNames.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/DotNames.java
index e96c6fe56867f..4dcaa0be357f6 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/DotNames.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/main/java/io/quarkus/rest/client/reactive/deployment/DotNames.java
@@ -1,5 +1,7 @@
package io.quarkus.rest.client.reactive.deployment;
+import java.lang.reflect.Method;
+
import javax.ws.rs.client.ClientRequestFilter;
import javax.ws.rs.client.ClientResponseFilter;
@@ -28,6 +30,8 @@ public class DotNames {
public static final DotName CLIENT_RESPONSE_FILTER = DotName.createSimple(ClientResponseFilter.class.getName());
public static final DotName CLIENT_EXCEPTION_MAPPER = DotName.createSimple(ClientExceptionMapper.class.getName());
+ static final DotName METHOD = DotName.createSimple(Method.class.getName());
+
private DotNames() {
}
}
diff --git a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/error/clientexceptionmapper/RegisteredClientExceptionMapperTest.java b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/error/clientexceptionmapper/RegisteredClientExceptionMapperTest.java
index 81fdcee50add0..92ead62d1a898 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/error/clientexceptionmapper/RegisteredClientExceptionMapperTest.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/deployment/src/test/java/io/quarkus/rest/client/reactive/error/clientexceptionmapper/RegisteredClientExceptionMapperTest.java
@@ -4,6 +4,8 @@
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.lang.reflect.Method;
+
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Priorities;
@@ -97,8 +99,8 @@ public interface ClientNoProviders {
Dto get400();
@ClientExceptionMapper
- static DummyException map(Response response) {
- if (response.getStatus() == 404) {
+ static DummyException map(Response response, Method method) {
+ if ((response.getStatus() == 404) && method.getName().equals("get404")) {
return new DummyException();
}
return null;
@@ -118,8 +120,8 @@ public interface ClientWithRegisteredLowPriorityMapper {
Dto get400();
@ClientExceptionMapper
- static DummyException map(Response response) {
- if (response.getStatus() == 404) {
+ static DummyException map(Method method, Response response) {
+ if ((response.getStatus() == 404) && method.getName().equals("get404")) {
return new DummyException();
}
return null;
diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/ClientExceptionMapper.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/ClientExceptionMapper.java
index e8c092879734d..cd2baed7a6deb 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/ClientExceptionMapper.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/ClientExceptionMapper.java
@@ -23,7 +23,7 @@
*
* {@code
* @ClientExceptionMapper
- * static DummyException map(Response response) {
+ * static DummyException map(Response response, Method method) {
* if (response.getStatus() == 404) {
* return new DummyException();
* }
diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/MicroProfileRestClientResponseFilter.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/MicroProfileRestClientResponseFilter.java
index 61b8d685cfd6f..4e45f007d551f 100644
--- a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/MicroProfileRestClientResponseFilter.java
+++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/MicroProfileRestClientResponseFilter.java
@@ -33,7 +33,13 @@ public void filter(ClientRequestContext requestContext, ClientResponseContext re
RestClientRequestContext restClientContext = ((ClientRequestContextImpl) requestContext)
.getRestClientRequestContext();
ResponseImpl response = ClientResponseCompleteRestHandler.mapToResponse(restClientContext, false);
- Throwable throwable = exceptionMapper.toThrowable(response);
+ Throwable throwable;
+ if (exceptionMapper instanceof ResteasyReactiveResponseExceptionMapper) {
+ throwable = ((ResteasyReactiveResponseExceptionMapper) exceptionMapper).toThrowable(response,
+ restClientContext);
+ } else {
+ throwable = exceptionMapper.toThrowable(response);
+ }
if (throwable != null) {
throw new UnwrappableException(throwable);
}
diff --git a/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseExceptionMapper.java b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseExceptionMapper.java
new file mode 100644
index 0000000000000..2044d4c74f5b8
--- /dev/null
+++ b/extensions/resteasy-reactive/rest-client-reactive/runtime/src/main/java/io/quarkus/rest/client/reactive/runtime/ResteasyReactiveResponseExceptionMapper.java
@@ -0,0 +1,16 @@
+package io.quarkus.rest.client.reactive.runtime;
+
+import javax.ws.rs.core.Response;
+
+import org.eclipse.microprofile.rest.client.ext.ResponseExceptionMapper;
+import org.jboss.resteasy.reactive.client.impl.RestClientRequestContext;
+
+public interface ResteasyReactiveResponseExceptionMapper extends ResponseExceptionMapper {
+
+ T toThrowable(Response response, RestClientRequestContext context);
+
+ @Override
+ default T toThrowable(Response response) {
+ throw new IllegalStateException("should never be invoked");
+ }
+}
diff --git a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java
index 0872e5a31aa62..47dcf87d950ff 100644
--- a/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java
+++ b/independent-projects/resteasy-reactive/client/runtime/src/main/java/org/jboss/resteasy/reactive/client/impl/RestClientRequestContext.java
@@ -156,6 +156,14 @@ public void abort() {
restart(abortHandlerChain);
}
+ public Method getInvokedMethod() {
+ Object o = properties.get(MP_INVOKED_METHOD_PROP);
+ if (o instanceof Method) {
+ return (Method) o;
+ }
+ return null;
+ }
+
@Override
protected Throwable unwrapException(Throwable t) {
var res = super.unwrapException(t);
diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/BasicJavaNativeBuildIT.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/BasicJavaNativeBuildIT.java
index c61f9c8135d17..b846cb793f502 100644
--- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/BasicJavaNativeBuildIT.java
+++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/BasicJavaNativeBuildIT.java
@@ -48,6 +48,76 @@ public void shouldBuildNativeImage() throws Exception {
}
+ @Test
+ public void shouldBuildNativeImageWithCustomName() throws Exception {
+ final File projectDir = getProjectDir("basic-java-native-module");
+
+ final BuildResult build = runGradleWrapper(projectDir, "clean", "quarkusBuild", "-Dquarkus.package.type=native",
+ "-Dquarkus.package.output-name=test");
+
+ assertThat(build.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME);
+ final String buildOutput = build.getOutput();
+ // make sure the output log during the build contains some expected logs from the native-image process
+ CharSequence[] expectedOutput;
+ if (buildOutput.contains("Version info:")) { // Starting with 22.0 the native-image output changed
+ expectedOutput = new CharSequence[] { "Initializing...", "Performing analysis...",
+ "Finished generating 'test-runner' in" };
+ } else {
+ expectedOutput = new CharSequence[] { "(clinit):", "(typeflow):", "[total]:" };
+ }
+ assertThat(buildOutput)
+ .withFailMessage("native-image build log is missing certain expected log messages: \n\n %s", buildOutput)
+ .contains(expectedOutput)
+ .doesNotContain("Finished generating '" + NATIVE_IMAGE_NAME + "' in");
+ Path nativeImagePath = projectDir.toPath().resolve("build").resolve("test-runner");
+ assertThat(nativeImagePath).exists();
+ Process nativeImageProcess = runNativeImage(nativeImagePath.toAbsolutePath().toString());
+ try {
+ final String response = DevModeTestUtils.getHttpResponse("/hello");
+ assertThat(response)
+ .withFailMessage("Response %s for /hello was expected to contain the hello, but didn't", response)
+ .contains("hello");
+ } finally {
+ nativeImageProcess.destroy();
+ }
+
+ }
+
+ @Test
+ public void shouldBuildNativeImageWithCustomNameWithoutSuffix() throws Exception {
+ final File projectDir = getProjectDir("basic-java-native-module");
+
+ final BuildResult build = runGradleWrapper(projectDir, "clean", "quarkusBuild", "-Dquarkus.package.type=native",
+ "-Dquarkus.package.output-name=test", "-Dquarkus.package.add-runner-suffix=false");
+
+ assertThat(build.getTasks().get(":quarkusBuild")).isEqualTo(BuildResult.SUCCESS_OUTCOME);
+ final String buildOutput = build.getOutput();
+ // make sure the output log during the build contains some expected logs from the native-image process
+ CharSequence[] expectedOutput;
+ if (buildOutput.contains("Version info:")) { // Starting with 22.0 the native-image output changed
+ expectedOutput = new CharSequence[] { "Initializing...", "Performing analysis...",
+ "Finished generating 'test' in" };
+ } else {
+ expectedOutput = new CharSequence[] { "(clinit):", "(typeflow):", "[total]:" };
+ }
+ assertThat(buildOutput)
+ .withFailMessage("native-image build log is missing certain expected log messages: \n\n %s", buildOutput)
+ .contains(expectedOutput)
+ .doesNotContain("Finished generating '" + NATIVE_IMAGE_NAME + "' in");
+ Path nativeImagePath = projectDir.toPath().resolve("build").resolve("test");
+ assertThat(nativeImagePath).exists();
+ Process nativeImageProcess = runNativeImage(nativeImagePath.toAbsolutePath().toString());
+ try {
+ final String response = DevModeTestUtils.getHttpResponse("/hello");
+ assertThat(response)
+ .withFailMessage("Response %s for /hello was expected to contain the hello, but didn't", response)
+ .contains("hello");
+ } finally {
+ nativeImageProcess.destroy();
+ }
+
+ }
+
private Process runNativeImage(String nativeImage) throws IOException {
final ProcessBuilder processBuilder = new ProcessBuilder(nativeImage);
processBuilder.inheritIO();
diff --git a/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/NativeIntegrationTestIT.java b/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/NativeIntegrationTestIT.java
index b387532b8ab23..b22b4eab2df07 100644
--- a/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/NativeIntegrationTestIT.java
+++ b/integration-tests/gradle/src/test/java/io/quarkus/gradle/nativeimage/NativeIntegrationTestIT.java
@@ -19,4 +19,22 @@ public void nativeTestShouldRunIntegrationTest() throws Exception {
assertThat(testResult.getTasks().get(":testNative")).isEqualTo(BuildResult.SUCCESS_OUTCOME);
}
+ @Test
+ public void runNativeTestsWithOutputName() throws Exception {
+ final File projectDir = getProjectDir("it-test-basic-project");
+
+ final BuildResult testResult = runGradleWrapper(projectDir, "clean", "testNative",
+ "-Dquarkus.package.output-name=test");
+ assertThat(testResult.getTasks().get(":testNative")).isEqualTo(BuildResult.SUCCESS_OUTCOME);
+ }
+
+ @Test
+ public void runNativeTestsWithoutRunnerSuffix() throws Exception {
+ final File projectDir = getProjectDir("it-test-basic-project");
+
+ final BuildResult testResult = runGradleWrapper(projectDir, "clean", "testNative",
+ "-Dquarkus.package.add-runner-suffix=false");
+ assertThat(testResult.getTasks().get(":testNative")).isEqualTo(BuildResult.SUCCESS_OUTCOME);
+ }
+
}
diff --git a/integration-tests/istio/disable-native-profile b/integration-tests/istio/disable-native-profile
new file mode 100644
index 0000000000000..011a7cc4571d5
--- /dev/null
+++ b/integration-tests/istio/disable-native-profile
@@ -0,0 +1 @@
+This file disables the native profile in the parent pom.xml of this module.
\ No newline at end of file
diff --git a/integration-tests/istio/maven-invoker-way/pom.xml b/integration-tests/istio/maven-invoker-way/pom.xml
new file mode 100644
index 0000000000000..a449d28ccf71d
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/pom.xml
@@ -0,0 +1,345 @@
+
+
+ 4.0.0
+
+
+ io.quarkus
+ quarkus-integration-test-istio-parent
+ 999-SNAPSHOT
+
+
+ quarkus-integration-test-istio-invoker
+ Quarkus - Integration Tests - Istio - Invoker
+ Istio integration tests that need to use the maven invoker because they test various dependency related scenarios
+
+
+ ${skipTests}
+
+
+
+
+
+ io.quarkus
+ quarkus-container-image-docker
+ test
+
+
+ io.quarkus
+ quarkus-container-image-jib
+ test
+
+
+
+ io.quarkus
+ quarkus-test-maven
+ test
+
+
+ io.quarkus
+ quarkus-kubernetes
+ test
+
+
+ io.quarkus
+ quarkus-openshift
+ test
+
+
+ io.quarkus
+ quarkus-minikube
+ test
+
+
+ io.fabric8
+ kubernetes-httpclient-okhttp
+ test
+
+
+ io.dekorate
+ kubernetes-annotations
+ noapt
+
+
+ io.dekorate
+ openshift-annotations
+ noapt
+
+
+ io.dekorate
+ knative-annotations
+ noapt
+
+
+ io.quarkus
+ quarkus-resteasy
+ ${project.version}
+ test
+
+
+ *
+ *
+
+
+
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-kubernetes-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-openshift-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-minikube-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-container-image-docker-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-container-image-jib-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-resteasy-deployment
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+ io.quarkus
+ quarkus-junit5
+ ${project.version}
+ pom
+ test
+
+
+ *
+ *
+
+
+
+
+
+
+
+ src/it
+ true
+
+
+
+
+ maven-invoker-plugin
+
+
+ integration-tests
+
+ install
+ run
+ verify
+
+
+
+
+ ${project.build.directory}/it
+ true
+ verify
+ true
+ true
+ invoker.properties
+
+
+
+ maven-failsafe-plugin
+
+
+
+ integration-test
+ verify
+
+
+
+
+
+
+
+
+
+ disable-tests
+
+
+ !e2e-tests
+
+
+
+ true
+ true
+
+
+
+ kubernetes-e2e-tests
+
+
+ kubernetes-e2e-tests
+
+
+
+ true
+
+
+
+
+ maven-invoker-plugin
+
+
+ xds-*/pom.xml
+
+ ${skipTests}
+
+
+ -Dinvalid-on-purpose
+ success
+
+
+
+
+
+
+
+ openshift-e2e-tests
+
+
+ openshift-e2e-tests
+
+
+
+ true
+
+
+
+
+ maven-invoker-plugin
+
+
+ xds-*/pom.xml
+
+ ${skipTests}
+
+
+ -Dinvalid-on-purpose
+ success
+
+
+
+
+
+
+
+ knative-e2e-tests
+
+
+ knative-e2e-tests
+
+
+
+ true
+
+
+
+
+ maven-invoker-plugin
+
+
+ xds-*/pom.xml
+
+ ${skipTests}
+
+
+ -Dinvalid-on-purpose
+ success
+
+
+
+
+
+
+
+
+
+ windows
+
+
+
+ true
+
+
+
+
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/invoker.properties b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/invoker.properties
new file mode 100644
index 0000000000000..ecfda713b3e09
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/invoker.properties
@@ -0,0 +1,5 @@
+# invoker.goals=clean package -Dquarkus.container.build=true -Dquarkus.package.type=native
+# ensure that an attempt to deploy is made, but that the attempt fails (as we don't want to deploy this test application to a cluster that the runner of test may have configured)
+invoker.goals=clean package -Dquarkus.kubernetes.deploy=true ${kubernetes-client-master-url}
+# expect a failure since there is no Kubernetes cluster to deploy to
+invoker.buildResult = ${build-result}
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml
new file mode 100644
index 0000000000000..844e6b1e01200
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/pom.xml
@@ -0,0 +1,124 @@
+
+
+ 4.0.0
+ org.acme
+ xds-grpc
+ 0.1-SNAPSHOT
+
+ UTF-8
+ 3.0.0-M7
+ 11
+ UTF-8
+ 11
+
+
+
+
+ io.quarkus
+ quarkus-bom
+ @project.version@
+ pom
+ import
+
+
+
+
+
+ io.quarkus
+ quarkus-grpc-xds
+
+
+ io.quarkus
+ quarkus-resteasy
+
+
+ io.quarkus
+ quarkus-minikube
+
+
+ io.quarkus
+ quarkus-container-image-jib
+
+
+ io.quarkus
+ quarkus-junit5
+ test
+
+
+ io.rest-assured
+ rest-assured
+ test
+
+
+
+
+
+ io.quarkus
+ quarkus-maven-plugin
+ @project.version@
+
+
+
+ generate-code
+ build
+
+
+
+
+
+ maven-surefire-plugin
+ ${surefire-plugin.version}
+
+
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+ native
+
+
+ native
+
+
+
+ native
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ ${native.surefire.skip}
+
+
+
+ maven-failsafe-plugin
+ ${surefire-plugin.version}
+
+
+
+ integration-test
+ verify
+
+
+
+ ${project.build.directory}/${project.build.finalName}-runner
+ org.jboss.logmanager.LogManager
+ ${maven.home}
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloEndpoint.java b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloEndpoint.java
new file mode 100644
index 0000000000000..32d57f630205b
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloEndpoint.java
@@ -0,0 +1,37 @@
+package org.acme;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+import examples.GreeterGrpc;
+import examples.HelloReply;
+import examples.HelloRequest;
+import io.grpc.StatusRuntimeException;
+import io.quarkus.grpc.GrpcClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Path("/hello")
+public class HelloEndpoint {
+ private static final Logger log = LoggerFactory.getLogger(HelloEndpoint.class);
+
+ @GrpcClient
+ GreeterGrpc.GreeterBlockingStub stub;
+
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public String hello() {
+ HelloRequest request = HelloRequest.newBuilder().setName("XDS gRPC").build();
+ HelloReply response;
+ try {
+ response = stub.sayHello(request);
+ } catch (StatusRuntimeException e) {
+ String msg = "RPC failed: " + e.getStatus();
+ log.warn(msg);
+ return msg;
+ }
+ return response.getMessage();
+ }
+}
\ No newline at end of file
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloService.java b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloService.java
new file mode 100644
index 0000000000000..4f86355a826ff
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/java/org/acme/HelloService.java
@@ -0,0 +1,16 @@
+package org.acme;
+
+import examples.GreeterGrpc;
+import examples.HelloReply;
+import examples.HelloRequest;
+import io.grpc.stub.StreamObserver;
+import io.quarkus.grpc.GrpcService;
+
+@GrpcService
+public class HelloService extends GreeterGrpc.GreeterImplBase {
+ @Override
+ public void sayHello(HelloRequest request, StreamObserver responseObserver) {
+ responseObserver.onNext(HelloReply.newBuilder().setMessage("Hello " + request.getName()).build());
+ responseObserver.onCompleted();
+ }
+}
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/proto/helloworld.proto b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/proto/helloworld.proto
new file mode 100644
index 0000000000000..5e400c9d4549c
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/proto/helloworld.proto
@@ -0,0 +1,53 @@
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+syntax = "proto3";
+
+option java_multiple_files = true;
+option java_package = "examples";
+option java_outer_classname = "HelloWorldProto";
+option objc_class_prefix = "HLW";
+
+package helloworld;
+
+// The greeting service definition.
+service Greeter {
+ // Sends a greeting
+ rpc SayHello (HelloRequest) returns (HelloReply) {}
+}
+
+// The request message containing the user's name.
+message HelloRequest {
+ string name = 1;
+}
+
+// The response message containing the greetings
+message HelloReply {
+ string message = 1;
+}
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/resources/application.properties b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/resources/application.properties
new file mode 100644
index 0000000000000..0230b4c1ae18d
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/src/main/resources/application.properties
@@ -0,0 +1,18 @@
+# Configuration file
+# key = value
+quarkus.container-image.registry=docker.io
+quarkus.kubernetes-client.trust-certs=true
+
+# XDS
+quarkus.grpc.server.xds.enabled=true
+quarkus.grpc.server.port=30051
+
+quarkus.grpc.clients.stub.name-resolver=xds
+quarkus.grpc.clients.stub.host=xds-grpc
+quarkus.grpc.clients.stub.port=30051
+
+# K8s
+quarkus.kubernetes.deployment-target=minikube
+quarkus.kubernetes.ports.grpc.container-port=30051
+quarkus.kubernetes.annotations."inject.istio.io/templates"=grpc-agent
+quarkus.kubernetes.annotations."proxy.istio.io/config"={"holdApplicationUntilProxyStarts": true}
diff --git a/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/verify.groovy b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/verify.groovy
new file mode 100644
index 0000000000000..a350ee928eb6c
--- /dev/null
+++ b/integration-tests/istio/maven-invoker-way/src/it/xds-grpc/verify.groovy
@@ -0,0 +1,63 @@
+import io.dekorate.utils.Serialization
+import io.fabric8.kubernetes.api.model.KubernetesList
+import io.fabric8.kubernetes.api.model.apps.Deployment
+import io.fabric8.kubernetes.client.KubernetesClient
+import io.fabric8.kubernetes.client.KubernetesClientBuilder
+import io.fabric8.kubernetes.client.LocalPortForward
+import io.fabric8.kubernetes.client.okhttp.OkHttpClientFactory
+
+//Check that file exits
+String base = basedir
+File kubernetesYml = new File(base, "target/kubernetes/minikube.yml")
+assert kubernetesYml.exists()
+
+// Workaround CNFE at shutdown
+this.class.getClassLoader().loadClass("io.fabric8.kubernetes.client.KubernetesClientException\$RequestMetadata")
+
+kubernetesYml.withInputStream { stream ->
+ //Check that its parse-able
+ KubernetesList list = Serialization.unmarshalAsList(stream)
+ assert list != null
+
+ Deployment deployment = list.items.find { r -> r.kind == "Deployment" }
+
+ //Check that ti contains a Deployment named after the project
+ assert deployment != null
+ assert deployment.metadata.name == "xds-grpc"
+
+ try (KubernetesClient client = new KubernetesClientBuilder()
+ .withHttpClientFactory(new OkHttpClientFactory())
+ .build()) {
+ try (LocalPortForward p = client.services().withName("xds-grpc").portForward(8080)) {
+ URL url = new URL(String.format("http://localhost:%s/hello", p.localPort));
+
+ int tries = 10;
+ String response = null;
+ while (response == null && tries > 0) {
+ try {
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setRequestMethod("GET");
+ int responseCode = connection.getResponseCode();
+ if (responseCode == HttpURLConnection.HTTP_OK) {
+ try (BufferedReader input = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
+ String line;
+ StringBuffer buffer = new StringBuffer();
+ while ((line = input.readLine()) != null) {
+ buffer.append(line);
+ }
+ response = buffer.toString();
+ }
+ break;
+ }
+ } catch (Exception e) {
+ System.err.print("Error: ")
+ System.err.println(e.getMessage());
+ }
+ Thread.sleep(6_000); // 6sec
+ tries--;
+ }
+ assert tries > 0
+ assert response != null && response == "Hello XDS gRPC"
+ }
+ }
+}
\ No newline at end of file
diff --git a/integration-tests/istio/pom.xml b/integration-tests/istio/pom.xml
new file mode 100644
index 0000000000000..dfae51b7a3241
--- /dev/null
+++ b/integration-tests/istio/pom.xml
@@ -0,0 +1,19 @@
+
+
+ 4.0.0
+
+ quarkus-integration-tests-parent
+ io.quarkus
+ 999-SNAPSHOT
+
+
+ quarkus-integration-test-istio-parent
+ Quarkus - Integration Tests - Istio - Parent
+ pom
+
+
+ maven-invoker-way
+
+
+
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 883bdad8fde3e..0ff20afb3af62 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -342,6 +342,7 @@
grpc-stork-response-time
google-cloud-functions-http
google-cloud-functions
+ istio