diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8027b81e9..b7569ee84 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -22,7 +22,7 @@ jobs:
check-latest: true
- name: Build Quarkus 3.14
run: |
- git clone -b 3.14 https://github.com/quarkusio/quarkus.git && cd quarkus && ./mvnw -B -s .github/mvn-settings.xml clean install -Dquickly -Dno-test-modules -Prelocations
+ git clone -b 3.14 https://github.com/quarkusio/quarkus.git && cd quarkus && ./mvnw -B --no-transfer-progress -s .github/mvn-settings.xml clean install -Dquickly -Dno-test-modules -Prelocations
- name: Tar Maven Repo
shell: bash
run: tar -I 'pigz -9' -cf maven-repo.tgz -C ~ .m2/repository
@@ -57,7 +57,7 @@ jobs:
run: tar -xzf maven-repo.tgz -C ~
- name: Build with Maven
run: |
- mvn -V -B -s .github/mvn-settings.xml verify -Dall-modules -Dvalidate-format -DskipTests -DskipITs -Dquarkus.container-image.build=false -Dquarkus.container-image.push=false
+ mvn -V -B --no-transfer-progress -s .github/mvn-settings.xml verify -Dall-modules -Dvalidate-format -DskipTests -DskipITs -Dquarkus.container-image.build=false -Dquarkus.container-image.push=false
detect-test-suite-modules:
name: Detect Modules in PR
runs-on: ubuntu-latest
@@ -156,7 +156,7 @@ jobs:
./quarkus-dev-cli version
- name: Build with Maven
run: |
- mvn -fae -V -B -s .github/mvn-settings.xml clean verify -Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli"${{ matrix.module-mvn-args }} -am -DexcludedGroups=long-running
+ mvn -fae -V -B --no-transfer-progress -s .github/mvn-settings.xml clean verify -Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli"${{ matrix.module-mvn-args }} -am -DexcludedGroups=long-running
- name: Detect flaky tests
id: flaky-test-detector
if: ${{ hashFiles('**/flaky-run-report.json') != '' }}
@@ -210,7 +210,7 @@ jobs:
./quarkus-dev-cli version
- name: Build with Maven
run: |
- mvn -fae -V -B -s .github/mvn-settings.xml -fae \
+ mvn -fae -V -B --no-transfer-progress -s .github/mvn-settings.xml -fae \
-Dquarkus.native.native-image-xmx=5g \
-Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli" \
${{ matrix.module-mvn-args }} clean verify -Dnative -am -DexcludedGroups=long-running
@@ -264,7 +264,7 @@ jobs:
MODULES_MAVEN_PARAM="-pl ${MODULES_ARG}"
fi
- mvn -B -fae -s .github/mvn-settings.xml clean verify -Dall-modules $MODULES_MAVEN_PARAM -am -DexcludedGroups=long-running
+ mvn -B --no-transfer-progress -fae -s .github/mvn-settings.xml clean verify -Dall-modules $MODULES_MAVEN_PARAM -am -DexcludedGroups=long-running
- name: Detect flaky tests
id: flaky-test-detector
if: ${{ hashFiles('**/flaky-run-report.json') != '' }}
diff --git a/.github/workflows/daily.yaml b/.github/workflows/daily.yaml
index 7c29b7b24..57fb4a71f 100644
--- a/.github/workflows/daily.yaml
+++ b/.github/workflows/daily.yaml
@@ -24,7 +24,7 @@ jobs:
check-latest: true
- name: Build Quarkus main
run: |
- git clone https://github.com/quarkusio/quarkus.git && cd quarkus && ./mvnw -B -s .github/mvn-settings.xml clean install -Dquickly -Dno-test-modules -Prelocations
+ git clone https://github.com/quarkusio/quarkus.git && cd quarkus && ./mvnw -B --no-transfer-progress -s .github/mvn-settings.xml clean install -Dquickly -Dno-test-modules -Prelocations
- name: Tar Maven Repo
shell: bash
run: tar -I 'pigz -9' -cf maven-repo.tgz -C ~ .m2/repository
@@ -73,7 +73,7 @@ jobs:
./quarkus-dev-cli version
- name: Test in JVM mode
run: |
- mvn -fae -V -B -s .github/mvn-settings.xml -fae clean verify -P ${{ matrix.profiles }} -Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli"
+ mvn -fae -V -B --no-transfer-progress -s .github/mvn-settings.xml -fae clean verify -P ${{ matrix.profiles }} -Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli"
- name: Zip Artifacts
if: failure()
run: |
@@ -127,7 +127,7 @@ jobs:
./quarkus-dev-cli version
- name: Test in Native mode
run: |
- mvn -fae -V -B -s .github/mvn-settings.xml -P ${{ matrix.profiles }} -fae clean verify -Dnative \
+ mvn -fae -V -B --no-transfer-progress -s .github/mvn-settings.xml -P ${{ matrix.profiles }} -fae clean verify -Dnative \
-Dquarkus.native.builder-image=quay.io/quarkus/${{ matrix.image }} \
-Dquarkus.native.native-image-xmx=5g \
-Dinclude.quarkus-cli-tests -Dts.quarkus.cli.cmd="${PWD}/quarkus-dev-cli"
@@ -168,7 +168,7 @@ jobs:
- name: Build in JVM mode
shell: bash
run: |
- mvn -B -fae -s .github/mvn-settings.xml clean verify
+ mvn -B --no-transfer-progress -fae -s .github/mvn-settings.xml clean verify
- name: Zip Artifacts
shell: bash
if: failure()
@@ -222,7 +222,7 @@ jobs:
shell: bash
run: |
# Running only http/http-minimum as after some time, it gives disk full in Windows when running on Native.
- mvn -B -fae -s .github/mvn-settings.xml clean verify -Dall-modules -Dnative -Dquarkus.native.container-build=false -pl http/http-minimum
+ mvn -B --no-transfer-progress -fae -s .github/mvn-settings.xml clean verify -Dall-modules -Dnative -Dquarkus.native.container-build=false -pl http/http-minimum
- name: Zip Artifacts
shell: bash
if: failure()
diff --git a/build/podman/pom.xml b/build/podman/pom.xml
index 36378ceff..817c3ea1a 100644
--- a/build/podman/pom.xml
+++ b/build/podman/pom.xml
@@ -55,5 +55,37 @@
+
+ openshift
+
+
+ openshift
+
+
+
+
+
+ maven-surefire-plugin
+
+ true
+
+
+
+ maven-failsafe-plugin
+
+ true
+
+
+
+ ${quarkus.platform.group-id}
+ quarkus-maven-plugin
+ ${quarkus.platform.version}
+
+ true
+
+
+
+
+
diff --git a/http/grpc/src/main/java/io/quarkus/ts/http/grpc/GrpcReflectionResponse.java b/http/grpc/src/main/java/io/quarkus/ts/http/grpc/GrpcReflectionResponse.java
index bb86462ca..e20a24b06 100644
--- a/http/grpc/src/main/java/io/quarkus/ts/http/grpc/GrpcReflectionResponse.java
+++ b/http/grpc/src/main/java/io/quarkus/ts/http/grpc/GrpcReflectionResponse.java
@@ -3,8 +3,11 @@
import java.util.List;
public final class GrpcReflectionResponse {
- private final int serviceCount;
- private final List serviceList;
+ private int serviceCount;
+ private List serviceList;
+
+ public GrpcReflectionResponse() {
+ }
public GrpcReflectionResponse(int serviceCount, List serviceList) {
this.serviceCount = serviceCount;
@@ -19,4 +22,11 @@ public int getServiceCount() {
return serviceCount;
}
+ public void setServiceCount(int serviceCount) {
+ this.serviceCount = serviceCount;
+ }
+
+ public void setServiceList(List serviceList) {
+ this.serviceList = serviceList;
+ }
}
diff --git a/http/grpc/src/main/resources/application.properties b/http/grpc/src/main/resources/application.properties
index f5b226b12..39fb43832 100644
--- a/http/grpc/src/main/resources/application.properties
+++ b/http/grpc/src/main/resources/application.properties
@@ -9,13 +9,31 @@ quarkus.grpc.server.enable-reflection-service=true
quarkus.grpc.clients.reflection-service.port=${quarkus.grpc.clients.plain.port}
quarkus.grpc.clients.streaming.port=${quarkus.grpc.clients.plain.port}
-%ssl.quarkus.grpc.clients.plain.ssl.trust-store=tls/ca.pem
-%ssl.quarkus.grpc.clients.reflection-service.ssl.trust-store=${quarkus.grpc.clients.plain.ssl.trust-store}
-%ssl.quarkus.grpc.clients.streaming.ssl.trust-store=${quarkus.grpc.clients.plain.ssl.trust-store}
+%ssl.quarkus.grpc.clients.plain.ssl.trust-store=${grpc.client.ca-cert}
+%ssl.quarkus.grpc.clients.reflection-service.ssl.trust-store=${grpc.client.ca-cert}
+%ssl.quarkus.grpc.clients.streaming.ssl.trust-store=${grpc.client.ca-cert}
# See https://github.com/quarkusio/quarkus/issues/38965 to learn, why we use these parameters
%ssl.quarkus.grpc.clients.plain.port=${quarkus.http.ssl-port}
-%ssl.quarkus.http.ssl.certificate.files=tls/server.pem
-%ssl.quarkus.http.ssl.certificate.key-files=tls/server.key
-%ssl.quarkus.grpc.server.ssl.certificate=tls/server.pem
-%ssl.quarkus.grpc.server.ssl.key=tls/server.key
\ No newline at end of file
+%ssl.quarkus.http.ssl.certificate.files=${grpc.server.cert}
+%ssl.quarkus.http.ssl.certificate.key-files=${grpc.server.key}
+%ssl.quarkus.grpc.server.ssl.certificate=${grpc.server.cert}
+%ssl.quarkus.grpc.server.ssl.key=${grpc.server.key}
+
+%mtls.quarkus.http.insecure-requests=disabled
+%mtls.quarkus.grpc.server.plain-text=false
+%mtls.quarkus.grpc.clients.plain.tls-configuration-name=mtls-client
+%mtls.quarkus.grpc.clients.reflection-service.tls-configuration-name=mtls-client
+%mtls.quarkus.grpc.clients.streaming.tls-configuration-name=mtls-client
+%mtls.quarkus.grpc.clients.plain.tls.enabled=true
+%mtls.quarkus.grpc.clients.reflection-service.tls.enabled=true
+%mtls.quarkus.grpc.clients.streaming.tls.enabled=true
+%mtls.quarkus.grpc.clients.plain.plain-text=false
+%mtls.quarkus.grpc.clients.reflection-service.plain-text=false
+%mtls.quarkus.grpc.clients.streaming.plain-text=false
+%mtls.quarkus.grpc.clients.reflection-service.use-quarkus-grpc-client=true
+%mtls.quarkus.grpc.clients.streaming.use-quarkus-grpc-client=true
+%mtls.quarkus.grpc.clients.plain.port=${quarkus.http.ssl-port}
+%mtls.quarkus.tls.mtls-client.key-store.pem.0.cert=${grpc.client.crt}
+%mtls.quarkus.tls.mtls-client.key-store.pem.0.key=${grpc.client.key}
+%mtls.quarkus.tls.mtls-client.trust-store.pem.certs=${grpc.client.ca-crt}
diff --git a/http/grpc/src/main/resources/tls/ca.cnf b/http/grpc/src/main/resources/tls/ca.cnf
deleted file mode 100644
index 936c6c90f..000000000
--- a/http/grpc/src/main/resources/tls/ca.cnf
+++ /dev/null
@@ -1,6 +0,0 @@
-[req]
-req_extensions = v3_req
-
-[v3_req]
-basicConstraints = CA:true
-keyUsage = critical, keyCertSign
\ No newline at end of file
diff --git a/http/grpc/src/main/resources/tls/ca.pem b/http/grpc/src/main/resources/tls/ca.pem
deleted file mode 100644
index bb2986a4c..000000000
--- a/http/grpc/src/main/resources/tls/ca.pem
+++ /dev/null
@@ -1,21 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIUTbmeWmNplPK5ZjMS7M+eSFtN2YkwDQYJKoZIhvcNAQEL
-BQAwUDELMAkGA1UEBhMCQ1oxDDAKBgNVBAgMA0pNSzENMAsGA1UEBwwEQnJubzEP
-MA0GA1UECgwGUmVkSGF0MRMwEQYDVQQLDApRdWFya3VzLVFFMB4XDTI0MDIyNzA4
-MzA1MloXDTM0MDIyNDA4MzA1MlowUDELMAkGA1UEBhMCQ1oxDDAKBgNVBAgMA0pN
-SzENMAsGA1UEBwwEQnJubzEPMA0GA1UECgwGUmVkSGF0MRMwEQYDVQQLDApRdWFy
-a3VzLVFFMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs/0x9/YIoueQ
-ckoItGRuW8CUc9kpdS35wfxcqrlyfQbo2i4idg5V9d4EYU3ONpvVl69O97t3DnXp
-XC90Mt+ActinPXs//ulxVelP5uVWo4nQILk889GHRfoIvsEKe+YZKTBxT92PJEDh
-qs1eDK5OJApX6ZRhHqZRjxVPRgwOhUE47qIHflDE0wX54zDPHGtwdSJtlDWSfbRg
-BLLzni50XAAPoEmHRb557yjYR6A3SfAE/Oaz++kh5HyDTrufGRQpn8R6MR2X8lJG
-FDSMqoCsf9AOtGzrpq8EoJb5hwBC7ko599beXb1A3PuYqQ4XU9gGCtTs3HHx2Am4
-t9fwS5OCmwIDAQABoz8wPTAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwICBDAd
-BgNVHQ4EFgQUo9s3q9xO/KVtZ4hiDyCsHmXWI+kwDQYJKoZIhvcNAQELBQADggEB
-AK/G72vu1xyITXJZeoi7pyj0iDk4nn0T6Znl5BaMZ5ukjxVH7EuIAOuCOOeDiYhe
-3WdwWHbxGdaZhJH9SF4CoCKNapVL1567lT0MU9JxfNWot8ipZ1J5WCHpor5HNl1D
-c072uEHQ7lTlErrvMDppPt6xb7dhXSVHneXve+RbyF8spzeKG31yg5DPkSiaIP8p
-qNnGw++J1Il0CQA11hYlH4wUE80atWEugTx04BHiK/HtYLQsbHKVSNw4gj7eFr//
-sQW0fliWPjmXLxAUU2efU/w6vs37LCuHApaN80yxTbK3J5LiPD8kH/OWRkPEcts9
-f2lZYZzQcMQvjbaSJ/cSzM0=
------END CERTIFICATE-----
diff --git a/http/grpc/src/main/resources/tls/server.key b/http/grpc/src/main/resources/tls/server.key
deleted file mode 100644
index 18714e74b..000000000
--- a/http/grpc/src/main/resources/tls/server.key
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCPCYGGsbW0zG6I
-TMvK85BF0jnd0L1U/XovBRCi3+VmrR2JovuazuKpmBwNyThsNLsj2KBLhYL6uwuB
-Kw0BeBW+yOaNB8gE7ef6MrT5qlp53X4XudmsucvdJnCSB01GC3GjElYe9rXrSuRH
-yPzU8QgpBAIJwFpbij/TWFUdynHUZ8oAjatzFlDzW4CoCTgo4NTdXhg5hsMSZvB0
-bkQ/jQF0PUvGCgbVthQGvSt75A69+ns8j2kxfb8DBrm94WpcxY1hMsVXP6/KZOyc
-rHlzVELAXJA0p0mHvokfQuU3xJT/Y5NbLDkq+9sh9sYjT5lw3tf0v99CrEOQgTC6
-jejADT2zAgMBAAECggEACKelGD7ZhVKXX5TyAdpCAQ+K49KVGjbqNT0juA8/JLrV
-3jWn7sKU8XkcPXNPADEin7UkYd12wvAdbpfpxgx7mFs0pBTz8+RnVHrL+41kwxn1
-Xr8mni5x2PRR/GwHr3TSz/C0mFQKRu31qShOsB3ThhPRgcCLVx2i5gliwRY2VAlK
-hZVmbhyC+4qF/BFNpzIIjyqNZsu8yjBP920DzX9TrQ7q0yQ5oE+Pyg5TMJPxUOiN
-dNiqNwVnQ77mz54eKJBDJbx431LS4Anp585AAruMj+7imGc7zbc4ZB4CtZ7x6f45
-3eBbiBhMepZ9wKg/Ym9aBdxxpy3gapZRs40DAJFC3QKBgQDBd1yINEnJ1ZZel/iA
-3rp8j/7rITz/bYIFkRqxihjRMSrdBKzTx3n3dnRKYjOh4B6CkWToaqRP3HPBVhKd
-pHjdz7Oo3PDrXnZcx41FUzYB7B0qkBD6vyqM9/U88da4ERtqNOczWCSHz/AQXfhc
-X5OlYA1Ed4tdLcyVqQL1/0Y7HwKBgQC9RVDFBh8vzMA5nr/gaZOwDee935Dmei7s
-AJqq6rRxkZEqSf7M090DUHaBTeg1jRMtGGNn6Q6LxaGe/jrRUvNTWVtOt1VfG8xZ
-r/3fM71VnhZ/m8D/rCOmNOYekKTITxNlBPGfDV9wUFFATNhyQCWQTbg4XmFzWQG7
-hEdalmk+7QKBgCMHU4+tt/Z9X5588ZeTvDw1bjhwajTtRO9xGF4w3NFzj4k5AXnO
-0jyGDAQzx5l1lNCbNqQGOv3ismq9BN3aG7A9nQ/kARL8pX2i++cja9HpSFaegxSD
-bFbdxl9kgjYNkuMl9P6M5QBaG+M6wG8pNvhobb6JzofudO5cDZcwwyyNAoGAWdtw
-rzlq0Py6PiDaI6a8ERdo8EIVvvY/FJhs1bw8ErbzXkpnB8OF6C7pNBZSqinh8sTj
-XM/OshkP1DYKopppHycLLGHpzA+cgvAE7VTZDK7TK548kKWe/yeaIOS29spkAM/K
-DqMArofTK13QXN2Ld+kODuTwCx00r1vrrFxAdzkCgYACF/hzTzT0BozFDT5Ve4sX
-fQBa4oZEiFOVqJ40ok3ICdqe22/38y5bQEoZ19TNmrK4nz/W+hOCpID26x/fel14
-MegjDjBfH77uwFgoI9O0uJiX4U89ZCOWmMXNH5wqqySJG+C+kF5ACONmGfaYrkPc
-8sjG1e5JXF2K5PxXHlRiIw==
------END PRIVATE KEY-----
diff --git a/http/grpc/src/main/resources/tls/server.pem b/http/grpc/src/main/resources/tls/server.pem
deleted file mode 100644
index 2c7e4694a..000000000
--- a/http/grpc/src/main/resources/tls/server.pem
+++ /dev/null
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDOzCCAiMCFH7N97KjoaAbXGiiEZBxz9YkgRvZMA0GCSqGSIb3DQEBCwUAMFAx
-CzAJBgNVBAYTAkNaMQwwCgYDVQQIDANKTUsxDTALBgNVBAcMBEJybm8xDzANBgNV
-BAoMBlJlZEhhdDETMBEGA1UECwwKUXVhcmt1cy1RRTAeFw0yNDAyMjcwODMxMjda
-Fw0zNDAyMjQwODMxMjdaMGQxCzAJBgNVBAYTAkNaMQwwCgYDVQQIDANKTUsxDTAL
-BgNVBAcMBEJybm8xDzANBgNVBAoMBlJlZEhhdDETMBEGA1UECwwKUXVhcmt1cy1R
-RTESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAjwmBhrG1tMxuiEzLyvOQRdI53dC9VP16LwUQot/lZq0diaL7ms7iqZgc
-Dck4bDS7I9igS4WC+rsLgSsNAXgVvsjmjQfIBO3n+jK0+apaed1+F7nZrLnL3SZw
-kgdNRgtxoxJWHva160rkR8j81PEIKQQCCcBaW4o/01hVHcpx1GfKAI2rcxZQ81uA
-qAk4KODU3V4YOYbDEmbwdG5EP40BdD1LxgoG1bYUBr0re+QOvfp7PI9pMX2/Awa5
-veFqXMWNYTLFVz+vymTsnKx5c1RCwFyQNKdJh76JH0LlN8SU/2OTWyw5KvvbIfbG
-I0+ZcN7X9L/fQqxDkIEwuo3owA09swIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQCM
-Yl1CFnKqP2LF/zZvdwiLkdaTbvefh4W0C31tLd2OaIGDo18cCr0OWAia2XD9f9f7
-dlTmDJhRT230S96/aR7FzT30OoyGFeuNq+C4M5d7lcwllKlG5zXupLl7D3l30fnf
-tUxUrFWbyh/xVGKRm4J2xP5MtIGOTfXBZsxqaawEN7U2bTmsA+/1vBWXJ+W2yCfs
-IoQPNH125wsDOiCvXDacn2jd+GxxZXtfv4UoZ3LZLGko5Tv4dubu1SwaC6oek2bc
-5trifNC9timIoKM0mqc4hdClB6YDDQ+pRLmy545B/EwP3xMmugnTkRo12miPLtGX
-TayJV9LQkMXHgn5tKTOp
------END CERTIFICATE-----
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GRPCIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GRPCIT.java
index e251cf25c..029f9020b 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GRPCIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GRPCIT.java
@@ -1,51 +1,55 @@
package io.quarkus.ts.http.grpc;
-import static org.hamcrest.CoreMatchers.is;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Iterator;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.HttpStatus;
-import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import io.grpc.Channel;
-import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
import io.quarkus.ts.grpc.GreeterGrpc;
import io.quarkus.ts.grpc.HelloReply;
import io.quarkus.ts.grpc.HelloRequest;
import io.quarkus.ts.grpc.StreamingGrpc;
+import io.vertx.mutiny.ext.web.client.WebClient;
public interface GRPCIT {
- RestService app();
+ CloseableManagedChannel getChannel();
- Channel getChannel();
+ WebClient getWebClient();
@Test
default void grpcClient() {
- app().given().get("/http/grpc").then()
- .statusCode(HttpStatus.SC_OK)
- .body(is("Hello grpc"));
+ var response = getWebClient().get("/http/grpc").sendAndAwait();
+ assertEquals(HttpStatus.SC_OK, response.statusCode());
+ assertTrue(response.bodyAsString().startsWith("Hello grpc"));
}
@Test
default void grpcServer() throws ExecutionException, InterruptedException {
- HelloRequest request = HelloRequest.newBuilder().setName("server").build();
- HelloReply response = GreeterGrpc.newFutureStub(getChannel()).sayHello(request).get();
- Assertions.assertEquals("Hello server", response.getMessage());
+ try (var channel = getChannel()) {
+ HelloRequest request = HelloRequest.newBuilder().setName("server").build();
+ HelloReply response = GreeterGrpc.newFutureStub(channel).sayHello(request).get();
+ assertEquals("Hello server", response.getMessage());
+ }
}
@Test
default void serverStream() {
- HelloRequest request = HelloRequest.newBuilder().setName("ServerStream").build();
- Iterator stream = StreamingGrpc.newBlockingStub(getChannel()).serverStream(request);
- AtomicInteger counter = new AtomicInteger(0);
- stream.forEachRemaining((reply) -> {
- Assertions.assertEquals("Hello ServerStream", reply.getMessage());
- counter.incrementAndGet();
- });
- Assertions.assertEquals(GrpcStreamingService.SERVER_STREAM_MESSAGES_COUNT, counter.get());
+ try (var channel = getChannel()) {
+ HelloRequest request = HelloRequest.newBuilder().setName("ServerStream").build();
+ Iterator stream = StreamingGrpc.newBlockingStub(channel).serverStream(request);
+ AtomicInteger counter = new AtomicInteger(0);
+ stream.forEachRemaining((reply) -> {
+ assertEquals("Hello ServerStream", reply.getMessage());
+ counter.incrementAndGet();
+ });
+ assertEquals(GrpcStreamingService.SERVER_STREAM_MESSAGES_COUNT, counter.get());
+ }
}
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcMutualTlsSeparateServerIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcMutualTlsSeparateServerIT.java
new file mode 100644
index 000000000..2bf897f49
--- /dev/null
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcMutualTlsSeparateServerIT.java
@@ -0,0 +1,79 @@
+package io.quarkus.ts.http.grpc;
+
+import static io.quarkus.test.security.certificate.CertificateBuilder.INSTANCE_KEY;
+import static io.quarkus.test.services.Certificate.Format.PEM;
+
+import org.junit.jupiter.api.Tag;
+import org.junit.jupiter.api.condition.OS;
+
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
+import io.quarkus.test.bootstrap.GrpcService;
+import io.quarkus.test.scenarios.QuarkusScenario;
+import io.quarkus.test.security.certificate.CertificateBuilder;
+import io.quarkus.test.security.certificate.PemClientCertificate;
+import io.quarkus.test.services.Certificate;
+import io.quarkus.test.services.Certificate.ClientCertificate;
+import io.quarkus.test.services.QuarkusApplication;
+import io.vertx.mutiny.ext.web.client.WebClient;
+
+@Tag("QUARKUS-4592")
+@QuarkusScenario
+public class GrpcMutualTlsSeparateServerIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
+
+ private static final String CERT_PREFIX = "grpc-mtls-separate-server";
+ private static final String CLIENT_CN_NAME = "mtls-client-name";
+ private static WebClient webClient = null;
+
+ @QuarkusApplication(grpc = true, ssl = true, certificates = @Certificate(prefix = CERT_PREFIX, clientCertificates = {
+ @ClientCertificate(cnAttribute = CLIENT_CN_NAME)
+ }, format = PEM, configureKeystore = true, configureTruststore = true, tlsConfigName = "mtls-server", configureHttpServer = true))
+ static final GrpcService app = (GrpcService) new GrpcService()
+ .withProperty("quarkus.http.ssl.client-auth", "required")
+ .withProperty("quarkus.profile", "mtls")
+ .withProperty("grpc.client.crt", GrpcMutualTlsSeparateServerIT::getClientCert)
+ .withProperty("grpc.client.ca-crt", GrpcMutualTlsSeparateServerIT::getClientCaCert)
+ .withProperty("grpc.client.key", GrpcMutualTlsSeparateServerIT::getClientKey);
+
+ public CloseableManagedChannel getChannel() {
+ return app.securedGrpcChannel();
+ }
+
+ @Override
+ public WebClient getWebClient() {
+ if (webClient == null) {
+ // HINT: we don't need to close HTTPS client as FW takes care of it
+ webClient = app.mutinyHttps(CLIENT_CN_NAME);
+ }
+ return webClient;
+ }
+
+ private static String getClientCert() {
+ return addEscapes(getClientCertificate().certPath());
+ }
+
+ private static String getClientCaCert() {
+ return addEscapes(getClientCertificate().truststorePath());
+ }
+
+ private static String getClientKey() {
+ return addEscapes(getClientCertificate().keyPath());
+ }
+
+ private static CertificateBuilder getCertificateBuilder() {
+ return app.getPropertyFromContext(CertificateBuilder.INSTANCE_KEY);
+ }
+
+ private static PemClientCertificate getClientCertificate() {
+ return (PemClientCertificate) getCertificateBuilder().findCertificateByPrefix(CERT_PREFIX)
+ .getClientCertificateByCn(CLIENT_CN_NAME);
+ }
+
+ static String addEscapes(String path) {
+ if (OS.WINDOWS.isCurrentOs()) {
+ // TODO: move this to the FW
+ // back-slashes have special meaning in Cygwin etc.
+ return path.replace("\\", "\\\\");
+ }
+ return path;
+ }
+}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcTlsSeparateServerIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcTlsSeparateServerIT.java
new file mode 100644
index 000000000..132237b05
--- /dev/null
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/GrpcTlsSeparateServerIT.java
@@ -0,0 +1,68 @@
+package io.quarkus.ts.http.grpc;
+
+import static io.quarkus.test.services.Certificate.Format.PEM;
+import static io.quarkus.ts.http.grpc.GrpcMutualTlsSeparateServerIT.addEscapes;
+
+import org.junit.jupiter.api.AfterAll;
+
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
+import io.quarkus.test.bootstrap.GrpcService;
+import io.quarkus.test.scenarios.QuarkusScenario;
+import io.quarkus.test.security.certificate.Certificate.PemCertificate;
+import io.quarkus.test.security.certificate.CertificateBuilder;
+import io.quarkus.test.services.Certificate;
+import io.quarkus.test.services.QuarkusApplication;
+import io.vertx.mutiny.ext.web.client.WebClient;
+
+@QuarkusScenario
+public class GrpcTlsSeparateServerIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
+
+ private static final String CERT_PREFIX = "grpc-tls-separate-server";
+ private static WebClient webClient = null;
+
+ @QuarkusApplication(grpc = true, ssl = true, certificates = @Certificate(prefix = CERT_PREFIX, format = PEM, configureKeystore = true, configureTruststore = true))
+ static final GrpcService app = (GrpcService) new GrpcService()
+ .withProperty("quarkus.profile", "ssl")
+ .withProperty("grpc.client.ca-cert", GrpcTlsSeparateServerIT::getClientCaCert)
+ .withProperty("grpc.server.cert", GrpcTlsSeparateServerIT::getServerCert)
+ .withProperty("grpc.server.key", GrpcTlsSeparateServerIT::getServerKey);
+
+ public CloseableManagedChannel getChannel() {
+ return app.securedGrpcChannel();
+ }
+
+ @Override
+ public WebClient getWebClient() {
+ if (webClient == null) {
+ webClient = app.mutiny();
+ }
+ return webClient;
+ }
+
+ @AfterAll
+ static void afterAll() {
+ if (webClient != null) {
+ webClient.close();
+ }
+ }
+
+ private static String getClientCaCert() {
+ return addEscapes(getPemCertificate().truststorePath());
+ }
+
+ private static String getServerCert() {
+ return addEscapes(getPemCertificate().certPath());
+ }
+
+ private static String getServerKey() {
+ return addEscapes(getPemCertificate().keyPath());
+ }
+
+ private static PemCertificate getPemCertificate() {
+ return (PemCertificate) getCertificateBuilder().findCertificateByPrefix(CERT_PREFIX);
+ }
+
+ private static CertificateBuilder getCertificateBuilder() {
+ return app.getPropertyFromContext(CertificateBuilder.INSTANCE_KEY);
+ }
+}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftExtensionGRPCIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftExtensionGRPCIT.java
index 5a89f396e..42b29d3a1 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftExtensionGRPCIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftExtensionGRPCIT.java
@@ -3,10 +3,10 @@
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Tag;
-import io.grpc.Channel;
-import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
import io.quarkus.test.scenarios.OpenShiftDeploymentStrategy;
import io.quarkus.test.scenarios.OpenShiftScenario;
+import io.vertx.mutiny.ext.web.client.WebClient;
@Tag("use-quarkus-openshift-extension")
@OpenShiftScenario(deployment = OpenShiftDeploymentStrategy.UsingOpenShiftExtension)
@@ -14,12 +14,12 @@
public class OpenShiftExtensionGRPCIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
@Override
- public RestService app() {
+ public CloseableManagedChannel getChannel() {
return null;
}
@Override
- public Channel getChannel() {
+ public WebClient getWebClient() {
return null;
}
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftGRPCIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftGRPCIT.java
index e6be7d08d..5361f5494 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftGRPCIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/OpenShiftGRPCIT.java
@@ -2,21 +2,21 @@
import org.junit.jupiter.api.Disabled;
-import io.grpc.Channel;
-import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
import io.quarkus.test.scenarios.OpenShiftScenario;
+import io.vertx.mutiny.ext.web.client.WebClient;
@OpenShiftScenario
@Disabled("https://github.com/quarkus-qe/quarkus-test-framework/issues/1052+1053")
public class OpenShiftGRPCIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
@Override
- public RestService app() {
+ public CloseableManagedChannel getChannel() {
return null;
}
@Override
- public Channel getChannel() {
+ public WebClient getWebClient() {
return null;
}
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/ReflectionHttpIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/ReflectionHttpIT.java
index 2b544b547..0a59fb21d 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/ReflectionHttpIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/ReflectionHttpIT.java
@@ -1,38 +1,33 @@
package io.quarkus.ts.http.grpc;
import static org.apache.http.HttpStatus.SC_OK;
-import static org.hamcrest.CoreMatchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.List;
-import org.hamcrest.Matchers;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.google.protobuf.Descriptors;
import com.google.protobuf.InvalidProtocolBufferException;
-import io.grpc.Channel;
import io.grpc.reflection.v1.FileDescriptorResponse;
-import io.quarkus.test.bootstrap.RestService;
import io.quarkus.ts.grpc.GreeterGrpc;
import io.quarkus.ts.grpc.HelloWorldProto;
import io.quarkus.ts.grpc.StreamingGrpc;
+import io.vertx.mutiny.ext.web.client.WebClient;
public interface ReflectionHttpIT {
- RestService app();
-
- Channel getChannel();
+ WebClient getWebClient();
@Test
default void testReflectionServices() {
- GrpcReflectionResponse response = app().given().when().get("/http/reflection/service/info")
- .then().statusCode(SC_OK).extract().response()
- .jsonPath().getObject(".", GrpcReflectionResponse.class);
+ var httpResponse = getWebClient().get("/http/reflection/service/info").sendAndAwait();
+ assertEquals(SC_OK, httpResponse.statusCode());
+ GrpcReflectionResponse response = httpResponse.bodyAsJson(GrpcReflectionResponse.class);
assertEquals(3, response.getServiceCount());
@@ -46,8 +41,9 @@ default void testReflectionServices() {
@Test
default void testReflectionMethods() throws InvalidProtocolBufferException {
- byte[] responseByteArray = app().given().when().get("/http/reflection/descriptor/greeting")
- .then().statusCode(SC_OK).extract().body().asByteArray();
+ var httpResponse = getWebClient().get("/http/reflection/descriptor/greeting").sendAndAwait();
+ assertEquals(SC_OK, httpResponse.statusCode());
+ byte[] responseByteArray = httpResponse.body().getBytes();
String fileDescriptor = FileDescriptorResponse.parseFrom(responseByteArray).toString();
@@ -75,8 +71,9 @@ default void testReflectionMethods() throws InvalidProtocolBufferException {
@Test
@DisplayName("GRPC reflection test - check service messages types")
default void testReflectionMessages() throws InvalidProtocolBufferException {
- byte[] responseByteArray = app().given().when().get("/http/reflection/descriptor/greeting")
- .then().statusCode(SC_OK).extract().body().asByteArray();
+ var httpResponse = getWebClient().get("/http/reflection/descriptor/greeting").sendAndAwait();
+ assertEquals(SC_OK, httpResponse.statusCode());
+ byte[] responseByteArray = httpResponse.body().getBytes();
String fileDescriptor = FileDescriptorResponse.parseFrom(responseByteArray).toString();
var messageTypes = HelloWorldProto.getDescriptor().getMessageTypes();
@@ -90,8 +87,9 @@ default void testReflectionMessages() throws InvalidProtocolBufferException {
@Test
@DisplayName("GRPC reflection test - check method SayHello of Greeter service exists and then call it")
default void testReflectionCallMethod() throws InvalidProtocolBufferException {
- byte[] responseByteArray = app().given().when().get("/http/reflection/descriptor/greeting")
- .then().statusCode(SC_OK).extract().body().asByteArray();
+ var httpResponse = getWebClient().get("/http/reflection/descriptor/greeting").sendAndAwait();
+ assertEquals(SC_OK, httpResponse.statusCode());
+ byte[] responseByteArray = httpResponse.body().getBytes();
String fileDescriptor = FileDescriptorResponse.parseFrom(responseByteArray).toString();
@@ -114,6 +112,8 @@ default void testReflectionCallMethod() throws InvalidProtocolBufferException {
assertTrue(fileDescriptor.contains("SayHello"));
// Call sayHello method and compare context
- app().given().when().get("/http/tester").then().statusCode(SC_OK).body(Matchers.is("Hello tester"));
+ httpResponse = getWebClient().get("/http/tester").sendAndAwait();
+ assertEquals(SC_OK, httpResponse.statusCode());
+ assertEquals("Hello tester", httpResponse.bodyAsString());
}
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SameServerIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SameServerIT.java
index 2f288b7cc..5766f7b8a 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SameServerIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SameServerIT.java
@@ -2,40 +2,37 @@
import org.junit.jupiter.api.AfterAll;
-import io.grpc.Channel;
-import io.grpc.ManagedChannel;
-import io.grpc.ManagedChannelBuilder;
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
import io.quarkus.test.bootstrap.GrpcService;
-import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.QuarkusApplication;
+import io.vertx.mutiny.ext.web.client.WebClient;
@QuarkusScenario
public class SameServerIT implements GRPCIT, ReflectionHttpIT, StreamingHttpIT {
+ private static WebClient webClient = null;
+
@QuarkusApplication(grpc = true)
static final GrpcService app = new GrpcService();
- private static ManagedChannel channel;
@Override
- public Channel getChannel() {
- if (channel == null) {
- channel = ManagedChannelBuilder.forAddress(
- app.getURI().getHost(),
- app.getURI().getPort())
- .usePlaintext()
- .build();
- }
- return channel;
+ public CloseableManagedChannel getChannel() {
+ return app.grpcChannel();
}
@Override
- public RestService app() {
- return app;
+ public WebClient getWebClient() {
+ if (webClient == null) {
+ webClient = app.mutiny();
+ }
+ return webClient;
}
@AfterAll
static void afterAll() {
- channel.shutdown();
+ if (webClient != null) {
+ webClient.close();
+ }
}
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/XeparateServerIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SeparateServerIT.java
similarity index 50%
rename from http/grpc/src/test/java/io/quarkus/ts/http/grpc/XeparateServerIT.java
rename to http/grpc/src/test/java/io/quarkus/ts/http/grpc/SeparateServerIT.java
index 63a30477a..e9f679b12 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/XeparateServerIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/SeparateServerIT.java
@@ -1,17 +1,17 @@
package io.quarkus.ts.http.grpc;
-import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.AfterAll;
-import io.grpc.Channel;
+import io.quarkus.test.bootstrap.CloseableManagedChannel;
import io.quarkus.test.bootstrap.GrpcService;
-import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.QuarkusApplication;
+import io.vertx.mutiny.ext.web.client.WebClient;
@QuarkusScenario
-@DisplayName("SeparateServer")
-//This test should be the last, or we get complains, that the channel was not shut down before closure. This is a bug in our framework.
-public class XeparateServerIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
+public class SeparateServerIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
+
+ private static WebClient webClient = null;
@QuarkusApplication(grpc = true)
static final GrpcService app = (GrpcService) new GrpcService()
@@ -19,13 +19,22 @@ public class XeparateServerIT implements GRPCIT, StreamingHttpIT, ReflectionHttp
.withProperty("quarkus.grpc.clients.plain.port", "${quarkus.grpc.server.port}");
@Override
- public Channel getChannel() {
+ public CloseableManagedChannel getChannel() {
return app.grpcChannel();
}
@Override
- public RestService app() {
- return app;
+ public WebClient getWebClient() {
+ if (webClient == null) {
+ webClient = app.mutiny();
+ }
+ return webClient;
}
+ @AfterAll
+ static void afterAll() {
+ if (webClient != null) {
+ webClient.close();
+ }
+ }
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/StreamingHttpIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/StreamingHttpIT.java
index 7019e5d6f..c0832066e 100644
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/StreamingHttpIT.java
+++ b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/StreamingHttpIT.java
@@ -5,24 +5,18 @@
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
-import io.quarkus.test.bootstrap.RestService;
-import io.restassured.http.ContentType;
-import io.restassured.response.Response;
-import io.restassured.specification.RequestSpecification;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.mutiny.ext.web.client.WebClient;
public interface StreamingHttpIT {
- RestService app();
-
- default RequestSpecification given() {
- return app().given();
- }
+ WebClient getWebClient();
@Test
default void serverStreaming() {
- Response response = given().when().get("/http/streaming/server/ServerStreaming");
+ var response = getWebClient().get("/http/streaming/server/ServerStreaming").sendAndAwait();
Assertions.assertEquals(200, response.statusCode());
- List responses = response.jsonPath().getList(".");
+ List> responses = response.bodyAsJsonArray().getList();
Assertions.assertEquals(GrpcStreamingService.SERVER_STREAM_MESSAGES_COUNT, responses.size());
responses.forEach(message -> Assertions.assertEquals("Hello ServerStreaming", message));
}
@@ -30,23 +24,21 @@ default void serverStreaming() {
@Test
default void clientStreaming() {
List names = List.of("Alice", "Bob", "Charlie");
- Response response = given().when()
- .contentType(ContentType.JSON)
- .body(names)
- .post("/http/streaming/client");
+ var response = getWebClient().post("/http/streaming/client")
+ .putHeader(HttpHeaders.CONTENT_TYPE.toString(), "application/json")
+ .sendJsonAndAwait(names);
Assertions.assertEquals(200, response.statusCode());
- Assertions.assertEquals("Total names submitted: " + names.size(), response.body().asString());
+ Assertions.assertEquals("Total names submitted: " + names.size(), response.bodyAsString());
}
@Test
default void bidirectional() {
List names = List.of("Alice", "Bob", "Charlie");
- Response response = given().when()
- .contentType(ContentType.JSON)
- .body(names)
- .post("/http/streaming/bi");
+ var response = getWebClient().post("/http/streaming/bi")
+ .putHeader(HttpHeaders.CONTENT_TYPE.toString(), "application/json")
+ .sendJsonAndAwait(names);
Assertions.assertEquals(200, response.statusCode());
- List messages = response.jsonPath().getList(".");
+ var messages = response.bodyAsJsonArray().getList();
Assertions.assertEquals(names.size() + 1, messages.size());
Assertions.assertEquals("Hello: Alice;Bob;Charlie;", messages.get(names.size()));
}
diff --git a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/TLSIT.java b/http/grpc/src/test/java/io/quarkus/ts/http/grpc/TLSIT.java
deleted file mode 100644
index bf985cd8c..000000000
--- a/http/grpc/src/test/java/io/quarkus/ts/http/grpc/TLSIT.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package io.quarkus.ts.http.grpc;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.junit.jupiter.api.AfterAll;
-
-import io.grpc.Channel;
-import io.grpc.ChannelCredentials;
-import io.grpc.Grpc;
-import io.grpc.ManagedChannel;
-import io.grpc.TlsChannelCredentials;
-import io.quarkus.test.bootstrap.GrpcService;
-import io.quarkus.test.bootstrap.Protocol;
-import io.quarkus.test.bootstrap.RestService;
-import io.quarkus.test.scenarios.QuarkusScenario;
-import io.quarkus.test.services.QuarkusApplication;
-import io.restassured.specification.RequestSpecification;
-
-@QuarkusScenario
-public class TLSIT implements GRPCIT, StreamingHttpIT, ReflectionHttpIT {
-
- private static ManagedChannel channel;
- @QuarkusApplication(grpc = true, ssl = true)
- static final GrpcService app = (GrpcService) new GrpcService()
- .withProperty("quarkus.profile", "ssl");
-
- public Channel getChannel() {
- if (channel != null) {
- return channel;
- }
- try (InputStream caCertificate = app.getClass().getClassLoader().getResourceAsStream("tls/ca.pem")) {
- ChannelCredentials credentials = TlsChannelCredentials.newBuilder()
- .trustManager(caCertificate)
- .build();
- channel = Grpc.newChannelBuilderForAddress(app().getURI(Protocol.GRPC).getHost(),
- app().getURI(Protocol.HTTPS).getPort(), credentials)
- .build();
- return channel;
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public RestService app() {
- return app;
- }
-
- @Override
- public RequestSpecification given() {
- return app().relaxedHttps().given();
- }
-
- @AfterAll
- static void afterAll() {
- channel.shutdown();
- }
-}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java
new file mode 100644
index 000000000..6db2a053e
--- /dev/null
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/CustomHeaderResponse.java
@@ -0,0 +1,13 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+public class CustomHeaderResponse {
+ private final String content;
+
+ public CustomHeaderResponse(String content) {
+ this.content = content;
+ }
+
+ public String getContent() {
+ return content;
+ }
+}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/DownloadResource.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/DownloadResource.java
new file mode 100644
index 000000000..833d6d25c
--- /dev/null
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/DownloadResource.java
@@ -0,0 +1,59 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+import java.io.File;
+import java.util.UUID;
+
+import jakarta.inject.Inject;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import io.smallrye.mutiny.Uni;
+import io.vertx.core.file.OpenOptions;
+import io.vertx.mutiny.core.Vertx;
+
+@Path("/download")
+public class DownloadResource {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DownloadResource.class);
+ private static final String TEST_FILE = System.getProperty("java.io.tmpdir") +
+ File.separator + "DownloadResource-" + UUID.randomUUID().toString() + "-test.txt";
+ private static final OpenOptions READ_ONLY = new OpenOptions().setWrite(false).setCreate(false);
+
+ @Inject
+ Vertx vertx;
+
+ @POST
+ @Path("/create")
+ public Uni createFile() {
+ LOGGER.info("Creating test file: {}", TEST_FILE);
+ return vertx.fileSystem()
+ .createFile(TEST_FILE)
+ .onItem().transform(it -> Response.ok(TEST_FILE).build());
+ }
+
+ @DELETE
+ @Path("/delete")
+ public Uni deleteFile() {
+ LOGGER.info("Deleting test file: {}", TEST_FILE);
+ return vertx.fileSystem()
+ .delete(TEST_FILE)
+ .onItem().transform(it -> Response.noContent().build());
+ }
+
+ @GET
+ @Produces(MediaType.APPLICATION_OCTET_STREAM)
+ public Uni downloadFile() {
+ LOGGER.info("Downloading test file: {}", TEST_FILE);
+ return vertx.fileSystem()
+ .open(TEST_FILE, READ_ONLY)
+ .onItem().transform(it -> Response.ok(it).build());
+ }
+}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingAbstractResource.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingAbstractResource.java
new file mode 100644
index 000000000..484db1f29
--- /dev/null
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingAbstractResource.java
@@ -0,0 +1,14 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+
+@Path("/greeting")
+public abstract class GreetingAbstractResource {
+
+ @GET
+ @Produces(MediaType.TEXT_PLAIN)
+ public abstract String hello();
+}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingResource.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingResource.java
new file mode 100644
index 000000000..7d4a99884
--- /dev/null
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/GreetingResource.java
@@ -0,0 +1,8 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+public class GreetingResource extends GreetingAbstractResource {
+ @Override
+ public String hello() {
+ return "Hello from Quarkus REST";
+ }
+}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java
new file mode 100644
index 000000000..ef0659767
--- /dev/null
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersMessageBodyWriter.java
@@ -0,0 +1,29 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class HeadersMessageBodyWriter implements MessageBodyWriter {
+
+ @Override
+ public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) {
+ return CustomHeaderResponse.class.isAssignableFrom(aClass) && MediaType.TEXT_PLAIN_TYPE.isCompatible(mediaType);
+ }
+
+ @Override
+ public void writeTo(CustomHeaderResponse customHeaderResponse, Class> aClass, Type type, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream)
+ throws IOException, WebApplicationException {
+ final String content = "Headers response: " + customHeaderResponse.getContent();
+ outputStream.write(content.getBytes());
+ }
+}
diff --git a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java
index 985646487..38544b37d 100644
--- a/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java
+++ b/http/http-advanced-reactive/src/main/java/io/quarkus/ts/http/advanced/reactive/HeadersResource.java
@@ -2,6 +2,8 @@
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import io.smallrye.mutiny.Uni;
@@ -28,4 +30,11 @@ public Uni headersOverride() {
return Uni.createFrom().item(response);
}
+ @GET
+ @Path("/no-accept")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Uni noAcceptHeaders() {
+ return Uni.createFrom().item(Response.ok(new CustomHeaderResponse("ok headers")).build());
+ }
+
}
diff --git a/http/http-advanced-reactive/src/main/resources/application.properties b/http/http-advanced-reactive/src/main/resources/application.properties
index d0ff80adb..ab80dc955 100644
--- a/http/http-advanced-reactive/src/main/resources/application.properties
+++ b/http/http-advanced-reactive/src/main/resources/application.properties
@@ -42,6 +42,8 @@ quarkus.keycloak.policy-enforcer.paths.multipart-form-data.path=/api/multipart-f
quarkus.keycloak.policy-enforcer.paths.multipart-form-data.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.hello.path=/api/hello/*
quarkus.keycloak.policy-enforcer.paths.hello.enforcement-mode=DISABLED
+quarkus.keycloak.policy-enforcer.paths.greeting.path=/api/greeting/*
+quarkus.keycloak.policy-enforcer.paths.greeting.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.grpc.path=/api/grpc/*
quarkus.keycloak.policy-enforcer.paths.grpc.enforcement-mode=DISABLED
quarkus.keycloak.policy-enforcer.paths.client.path=/api/client/*
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java
index fd8f9168a..c1f582705 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/BaseHttpAdvancedReactiveIT.java
@@ -62,6 +62,7 @@
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.scenarios.annotations.DisabledOnNative;
import io.quarkus.test.scenarios.annotations.EnabledOnQuarkusVersion;
import io.quarkus.test.security.certificate.CertificateBuilder;
import io.restassured.http.Header;
@@ -79,6 +80,7 @@ public abstract class BaseHttpAdvancedReactiveIT {
private static final String ROOT_PATH = "/api";
private static final String HELLO_ENDPOINT = ROOT_PATH + "/hello";
+ private static final String GREETING_ENDPOINT = ROOT_PATH + "/greeting";
private static final int TIMEOUT_SEC = 3;
private static final int RETRY = 3;
private static final String PASSWORD = "password";
@@ -95,6 +97,15 @@ public void httpServer() {
.body("content", is("Hello, World!"));
}
+ @Test
+ @DisplayName("Test Quarkus REST abstract resource with @Path")
+ @DisabledOnNative(reason = "https://github.com/quarkusio/quarkus/issues/42976")
+ public void abstractResourceWithPath() {
+ getApp().given().get(GREETING_ENDPOINT)
+ .then().statusCode(SC_OK)
+ .body(is("Hello from Quarkus REST"));
+ }
+
@Test
@DisplayName("GRPC Server test")
public void testGrpc() {
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java
index 9517aae89..53227b6e5 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeGrpcIntegrationReactiveIT.java
@@ -24,7 +24,6 @@
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.DevModeQuarkusApplication;
-import io.quarkus.test.services.URILike;
@Tag("QUARKUS-1026")
@Tag("QUARKUS-1094")
@@ -49,13 +48,7 @@ public class DevModeGrpcIntegrationReactiveIT {
};
@DevModeQuarkusApplication(grpc = true)
- static final GrpcService app = (GrpcService) new GrpcService() {
- @Override
- public URILike getGrpcHost() {
- // TODO: make app.grpcChannel() support gRPC on same HTTP server
- return super.getGrpcHost().withPort(app.getURI().getPort());
- }
- }
+ static final GrpcService app = (GrpcService) new GrpcService()
.withProperty("quarkus.oidc.enabled", "false")
.withProperty("quarkus.keycloak.policy-enforcer.enable", "false")
.withProperty("quarkus.keycloak.devservices.enabled", "false");
@@ -63,9 +56,11 @@ public URILike getGrpcHost() {
@Test
public void testGrpcAsClient() throws ExecutionException, InterruptedException {
HelloRequest request = HelloRequest.newBuilder().setName(NAME).build();
- HelloReply response = GreeterGrpc.newFutureStub(app.grpcChannel()).sayHello(request).get();
+ try (var channel = app.grpcChannel()) {
+ HelloReply response = GreeterGrpc.newFutureStub(channel).sayHello(request).get();
- assertEquals("Hello " + NAME, response.getMessage());
+ assertEquals("Hello " + NAME, response.getMessage());
+ }
}
@Test
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeHttpsIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeHttpsIT.java
index a0880978e..cf4d1af08 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeHttpsIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DevModeHttpsIT.java
@@ -13,7 +13,7 @@
@QuarkusScenario
public class DevModeHttpsIT extends AbstractDevModeIT {
- @DevModeQuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true))
+ @DevModeQuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true, useTlsRegistry = false, configureHttpServer = true))
static RestService app = new DevModeQuarkusService()
.withProperty("quarkus.oidc.enabled", "false")
.withProperty("quarkus.keycloak.policy-enforcer.enable", "false")
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DownloadResourceIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DownloadResourceIT.java
new file mode 100644
index 000000000..1d190f89e
--- /dev/null
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/DownloadResourceIT.java
@@ -0,0 +1,58 @@
+package io.quarkus.ts.http.advanced.reactive;
+
+import static io.restassured.RestAssured.given;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.stream.Collectors;
+
+import org.junit.Assert;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.DisabledOnOs;
+import org.junit.jupiter.api.condition.OS;
+
+import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.scenarios.QuarkusScenario;
+import io.quarkus.test.scenarios.annotations.DisabledOnNative;
+import io.quarkus.test.services.QuarkusApplication;
+import io.restassured.response.Response;
+
+/**
+ * Test makes sure AsyncFile gets closed, coverage triggered by https://github.com/quarkusio/quarkus/issues/41811
+ */
+@QuarkusScenario
+@DisabledOnNative(reason = "To save resources on CI")
+@DisabledOnOs(value = OS.WINDOWS, disabledReason = "No lsof command on Windows")
+class DownloadResourceIT {
+ @QuarkusApplication(classes = { DownloadResource.class }, properties = "oidcdisable.properties")
+ static RestService app = new RestService();
+
+ @Test
+ void ensureAsyncFileGetsClosed() throws IOException {
+ Response response = app.given()
+ .when().post("/download/create")
+ .then()
+ .statusCode(200)
+ .extract().response();
+ String file = response.getBody().asString();
+
+ app.given()
+ .when().get("/download")
+ .then()
+ .statusCode(200);
+
+ ProcessBuilder lsofBuilder = new ProcessBuilder("lsof", file);
+ Process lsofProcess = lsofBuilder.start();
+ String lsofOutput = new BufferedReader(new InputStreamReader(lsofProcess.getInputStream())).lines()
+ .collect(Collectors.joining("\n"));
+
+ app.given()
+ .when().delete("/download/delete")
+ .then()
+ .statusCode(204);
+
+ Assert.assertEquals("AsyncFile is not closed, details:\n" + lsofOutput + "\n", 0, lsofOutput.length());
+ }
+
+}
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java
index 5be721a99..1633ec1a6 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HeadersIT.java
@@ -16,12 +16,15 @@
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.QuarkusApplication;
+import io.restassured.http.Header;
import io.restassured.response.ValidatableResponse;
@QuarkusScenario
public class HeadersIT {
@QuarkusApplication(classes = { PathSpecificHeadersResource.class,
+ HeadersMessageBodyWriter.class,
+ CustomHeaderResponse.class,
HeadersResource.class }, properties = "headers.properties")
static RestService app = new RestService();
@@ -100,6 +103,19 @@ private ValidatableResponse whenGet(String path) {
.body(is("ok"));
}
+ @Test
+ @Tag("https://github.com/quarkusio/quarkus/pull/41411")
+ void testWithNoAcceptHeader() {
+ Header header = new Header("Accept", null);
+ given()
+ .when()
+ .header(header)
+ .get("/headers/no-accept")
+ .then()
+ .statusCode(200)
+ .body(is("Headers response: ok headers"));
+ }
+
/**
* Cache-Control header may be present multiple times in the response, e.g. in an OpenShift deployment. That is why we need
* to look for a specific value among all headers of the same name, and not just match the last one of them, which is what
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/Http2IT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/Http2IT.java
index 49319ba76..60be936cb 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/Http2IT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/Http2IT.java
@@ -43,7 +43,7 @@
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class Http2IT {
@QuarkusApplication(ssl = true, classes = { MorningResource.class,
- CustomFramesResource.class }, properties = "http2.properties", certificates = @Certificate(configureKeystore = true))
+ CustomFramesResource.class }, properties = "http2.properties", certificates = @Certificate(configureKeystore = true, configureHttpServer = true, useTlsRegistry = false))
static RestService app = new RestService();
private static URILike baseUri;
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HttpAdvancedReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HttpAdvancedReactiveIT.java
index 06fb08a72..544b8cdba 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HttpAdvancedReactiveIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/HttpAdvancedReactiveIT.java
@@ -19,7 +19,7 @@ public class HttpAdvancedReactiveIT extends BaseHttpAdvancedReactiveIT {
static KeycloakService keycloak = new KeycloakService(DEFAULT_REALM_FILE, DEFAULT_REALM, DEFAULT_REALM_BASE_PATH)
.withProperty("JAVA_OPTS", "-Dcom.redhat.fips=false");
- @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true))
+ @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true, configureHttpServer = true, useTlsRegistry = false))
static RestService app = new RestService().withProperty("quarkus.oidc.auth-server-url",
keycloak::getRealmUrl);
diff --git a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftHttpAdvancedReactiveIT.java b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftHttpAdvancedReactiveIT.java
index 515e55968..f7ec17339 100644
--- a/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftHttpAdvancedReactiveIT.java
+++ b/http/http-advanced-reactive/src/test/java/io/quarkus/ts/http/advanced/reactive/OpenShiftHttpAdvancedReactiveIT.java
@@ -23,7 +23,7 @@ public class OpenShiftHttpAdvancedReactiveIT extends BaseHttpAdvancedReactiveIT
static KeycloakService keycloak = new KeycloakService(DEFAULT_REALM_FILE, DEFAULT_REALM, DEFAULT_REALM_BASE_PATH)
.withProperty("JAVA_OPTS", "-Dcom.redhat.fips=false");
- @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true))
+ @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true, configureHttpServer = true, useTlsRegistry = false))
static RestService app = new RestService().withProperty("quarkus.oidc.auth-server-url",
keycloak::getRealmUrl);
diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java
new file mode 100644
index 000000000..d6a21773b
--- /dev/null
+++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/CustomHeaderResponse.java
@@ -0,0 +1,14 @@
+package io.quarkus.ts.http.advanced;
+
+public class CustomHeaderResponse {
+
+ private final String content;
+
+ public CustomHeaderResponse(String content) {
+ this.content = content;
+ }
+
+ public String getContent() {
+ return content;
+ }
+}
diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java
new file mode 100644
index 000000000..b3cbbb8fc
--- /dev/null
+++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersMessageBodyWriter.java
@@ -0,0 +1,29 @@
+package io.quarkus.ts.http.advanced;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.ext.MessageBodyWriter;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class HeadersMessageBodyWriter implements MessageBodyWriter {
+
+ @Override
+ public boolean isWriteable(Class aClass, Type type, Annotation[] annotations, MediaType mediaType) {
+ return CustomHeaderResponse.class.isAssignableFrom(aClass) && MediaType.TEXT_PLAIN_TYPE.isCompatible(mediaType);
+ }
+
+ @Override
+ public void writeTo(CustomHeaderResponse customHeaderResponse, Class> aClass, Type type, Annotation[] annotations,
+ MediaType mediaType, MultivaluedMap multivaluedMap, OutputStream outputStream)
+ throws IOException, WebApplicationException {
+ final String content = "Headers response: " + customHeaderResponse.getContent();
+ outputStream.write(content.getBytes());
+ }
+}
diff --git a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java
index 64d8aeadd..8ce1d1b97 100644
--- a/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java
+++ b/http/http-advanced/src/main/java/io/quarkus/ts/http/advanced/HeadersResource.java
@@ -2,6 +2,8 @@
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
@Path("/headers")
@@ -25,4 +27,10 @@ public Response headersOverride() {
return Response.ok("ok").header("foo", "abc").build();
}
+ @GET
+ @Path("/no-accept")
+ @Produces(MediaType.TEXT_PLAIN)
+ public Response noAcceptHeaders() {
+ return Response.ok(new CustomHeaderResponse("ok headers")).build();
+ }
}
diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java
index 7a3d5b323..e1a057dca 100644
--- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java
+++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/DevModeGrpcIntegrationIT.java
@@ -23,7 +23,6 @@
import io.quarkus.test.bootstrap.Protocol;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.DevModeQuarkusApplication;
-import io.quarkus.test.services.URILike;
@Tag("QUARKUS-1026")
@Tag("QUARKUS-1094")
@@ -47,13 +46,7 @@ public class DevModeGrpcIntegrationIT {
};
@DevModeQuarkusApplication(grpc = true)
- static final GrpcService app = (GrpcService) new GrpcService() {
- @Override
- public URILike getGrpcHost() {
- // TODO: make app.grpcChannel() support gRPC on same HTTP server
- return super.getGrpcHost().withPort(app.getURI().getPort());
- }
- }
+ static final GrpcService app = (GrpcService) new GrpcService()
.withProperty("quarkus.oidc.enabled", "false")
.withProperty("quarkus.keycloak.policy-enforcer.enable", "false")
.withProperty("quarkus.keycloak.devservices.enabled", "false");
@@ -61,9 +54,11 @@ public URILike getGrpcHost() {
@Test
public void testGrpcAsClient() {
HelloRequest request = HelloRequest.newBuilder().setName(NAME).build();
- HelloReply response = GreeterGrpc.newBlockingStub(app.grpcChannel()).sayHello(request);
+ try (var channel = app.grpcChannel()) {
+ HelloReply response = GreeterGrpc.newBlockingStub(channel).sayHello(request);
- assertEquals("Hello " + NAME, response.getMessage());
+ assertEquals("Hello " + NAME, response.getMessage());
+ }
}
@Test
diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java
index 741d94622..4e8ba99f1 100644
--- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java
+++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HeadersIT.java
@@ -16,12 +16,15 @@
import io.quarkus.test.bootstrap.RestService;
import io.quarkus.test.scenarios.QuarkusScenario;
import io.quarkus.test.services.QuarkusApplication;
+import io.restassured.http.Header;
import io.restassured.response.ValidatableResponse;
@QuarkusScenario
public class HeadersIT {
@QuarkusApplication(classes = { PathSpecificHeadersResource.class,
+ HeadersMessageBodyWriter.class,
+ CustomHeaderResponse.class,
HeadersResource.class }, properties = "headers.properties")
static RestService app = new RestService();
@@ -93,6 +96,21 @@ void testPathSpecificHeaderRulesOrder() {
cacheControlMatches(response, "max-age=1");
}
+ /**
+ * Coverage for https://github.com/quarkusio/quarkus/issues/41354 in RESTEasy classic
+ */
+ @Test
+ void testWithNoAcceptHeader() {
+ Header header = new Header("Accept", null);
+ given()
+ .when()
+ .header(header)
+ .get("/headers/no-accept")
+ .then()
+ .statusCode(200)
+ .body(is("Headers response: ok headers"));
+ }
+
private ValidatableResponse whenGet(String path) {
return given()
.get(path)
diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HttpAdvancedIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HttpAdvancedIT.java
index 7a9c33ade..ec5e8d810 100644
--- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HttpAdvancedIT.java
+++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/HttpAdvancedIT.java
@@ -19,7 +19,7 @@ public class HttpAdvancedIT extends BaseHttpAdvancedIT {
static KeycloakService keycloak = new KeycloakService(DEFAULT_REALM_FILE, DEFAULT_REALM, DEFAULT_REALM_BASE_PATH)
.withProperty("JAVA_OPTS", "-Dcom.redhat.fips=false");
- @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true))
+ @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true, configureHttpServer = true, useTlsRegistry = false))
static RestService app = new RestService().withProperty("quarkus.oidc.auth-server-url", keycloak::getRealmUrl);
@Override
diff --git a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/OpenShiftHttpAdvancedIT.java b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/OpenShiftHttpAdvancedIT.java
index 1cfcd7199..f115e38b4 100644
--- a/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/OpenShiftHttpAdvancedIT.java
+++ b/http/http-advanced/src/test/java/io/quarkus/ts/http/advanced/OpenShiftHttpAdvancedIT.java
@@ -23,7 +23,7 @@ public class OpenShiftHttpAdvancedIT extends BaseHttpAdvancedIT {
static KeycloakService keycloak = new KeycloakService(DEFAULT_REALM_FILE, DEFAULT_REALM, DEFAULT_REALM_BASE_PATH)
.withProperty("JAVA_OPTS", "-Dcom.redhat.fips=false");
- @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true))
+ @QuarkusApplication(ssl = true, certificates = @Certificate(configureKeystore = true, configureHttpServer = true, useTlsRegistry = false))
static RestService app = new RestService().withProperty("quarkus.oidc.auth-server-url", keycloak::getRealmUrl);
@Override
diff --git a/http/http-minimum-reactive/src/main/java/io/quarkus/ts/http/minimum/reactive/AbstractApplication.java b/http/http-minimum-reactive/src/main/java/io/quarkus/ts/http/minimum/reactive/AbstractApplication.java
new file mode 100644
index 000000000..48575d600
--- /dev/null
+++ b/http/http-minimum-reactive/src/main/java/io/quarkus/ts/http/minimum/reactive/AbstractApplication.java
@@ -0,0 +1,9 @@
+package io.quarkus.ts.http.minimum.reactive;
+
+import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+
+@ApplicationPath("/rest")
+public abstract class AbstractApplication extends Application {
+ // Abstract jakarta.ws.rs.core.Application classes should be ignored
+}
diff --git a/http/http-minimum/src/main/java/io/quarkus/ts/http/minimum/AbstractApplication.java b/http/http-minimum/src/main/java/io/quarkus/ts/http/minimum/AbstractApplication.java
new file mode 100644
index 000000000..175a6e2ca
--- /dev/null
+++ b/http/http-minimum/src/main/java/io/quarkus/ts/http/minimum/AbstractApplication.java
@@ -0,0 +1,10 @@
+package io.quarkus.ts.http.minimum;
+
+//import jakarta.ws.rs.ApplicationPath;
+import jakarta.ws.rs.core.Application;
+
+// TODO uncomment when https://github.com/quarkusio/quarkus/issues/42963 is fixed
+//@ApplicationPath("/rest")
+public abstract class AbstractApplication extends Application {
+ // Abstract jakarta.ws.rs.core.Application classes should be ignored
+}
diff --git a/http/management/src/main/java/io/quarkus/qe/ManagementRoute.java b/http/management/src/main/java/io/quarkus/qe/ManagementRoute.java
new file mode 100644
index 000000000..6a3d29fdb
--- /dev/null
+++ b/http/management/src/main/java/io/quarkus/qe/ManagementRoute.java
@@ -0,0 +1,13 @@
+package io.quarkus.qe;
+
+import jakarta.enterprise.event.Observes;
+
+import io.quarkus.vertx.http.ManagementInterface;
+
+public class ManagementRoute {
+
+ void setupCustomManagementRoute(@Observes ManagementInterface mi) {
+ mi.router().route("/management-ping").handler(ctx -> ctx.response().end("pong"));
+ }
+
+}
diff --git a/http/management/src/test/java/io/quarkus/qe/LocalOptionsIT.java b/http/management/src/test/java/io/quarkus/qe/LocalOptionsIT.java
index 331ea58af..50ca8e2f8 100644
--- a/http/management/src/test/java/io/quarkus/qe/LocalOptionsIT.java
+++ b/http/management/src/test/java/io/quarkus/qe/LocalOptionsIT.java
@@ -24,7 +24,7 @@ public class LocalOptionsIT {
static final RestService custom = new RestService()
.withProperty("quarkus.management.port", "9002");
- @QuarkusApplication(certificates = @Certificate(configureKeystoreForManagementInterface = true))
+ @QuarkusApplication(certificates = @Certificate(configureManagementInterface = true, configureKeystore = true, useTlsRegistry = false))
static final RestService tls = new RestService()
.withProperty("quarkus.management.port", "9003");
diff --git a/http/management/src/test/java/io/quarkus/qe/MutualTlsManagementInterfaceIT.java b/http/management/src/test/java/io/quarkus/qe/MutualTlsManagementInterfaceIT.java
new file mode 100644
index 000000000..bf71a31fa
--- /dev/null
+++ b/http/management/src/test/java/io/quarkus/qe/MutualTlsManagementInterfaceIT.java
@@ -0,0 +1,91 @@
+package io.quarkus.qe;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.apache.http.HttpStatus;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+
+import io.quarkus.test.bootstrap.RestService;
+import io.quarkus.test.scenarios.QuarkusScenario;
+import io.quarkus.test.security.certificate.CertificateBuilder;
+import io.quarkus.test.security.certificate.ClientCertificateRequest;
+import io.quarkus.test.services.Certificate;
+import io.quarkus.test.services.Certificate.ClientCertificate;
+import io.quarkus.test.services.QuarkusApplication;
+import io.quarkus.test.utils.AwaitilityUtils;
+
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+@QuarkusScenario
+public class MutualTlsManagementInterfaceIT {
+
+ private static final String CERT_PREFIX = "qe-test";
+ private static final String CLIENT_CN_1 = "client-cn-1";
+ private static final String CLIENT_CN_2 = "client-cn-2";
+ private static final String TLS_CONFIG_NAME = "mtls-management";
+
+ @QuarkusApplication(certificates = @Certificate(prefix = CERT_PREFIX, clientCertificates = {
+ @ClientCertificate(cnAttribute = CLIENT_CN_1),
+ @ClientCertificate(cnAttribute = CLIENT_CN_2, unknownToServer = true)
+ }, configureKeystore = true, configureTruststore = true, tlsConfigName = TLS_CONFIG_NAME, configureManagementInterface = true))
+ static final RestService app = new RestService()
+ .withProperty("quarkus.management.ssl.client-auth", "required")
+ .withProperty("quarkus.tls." + TLS_CONFIG_NAME + ".reload-period", "2s");
+
+ @Order(1)
+ @Test
+ public void testMutualTlsForManagementInterface() {
+ // test health probe
+ var client1 = app.mutinyHttps(CLIENT_CN_1);
+ var httpResponse = client1.get("/q/health").sendAndAwait();
+ assertEquals(HttpStatus.SC_OK, httpResponse.statusCode());
+
+ // test custom management endpoint
+ httpResponse = client1.get("/management-ping").sendAndAwait();
+ assertEquals("pong", httpResponse.bodyAsString());
+ assertEquals(HttpStatus.SC_OK, httpResponse.statusCode());
+
+ callManagementPingRouteAndExpectFailure(CLIENT_CN_2);
+ }
+
+ @Order(2)
+ @Test
+ public void testCertificateReloading() {
+ app
+ . getPropertyFromContext(CertificateBuilder.INSTANCE_KEY)
+ .regenerateCertificate(CERT_PREFIX, certRequest -> {
+ // regenerate client certificates
+ // make the first client invalid
+ var clientOneCert = new ClientCertificateRequest(CLIENT_CN_1, true);
+ // make the second client valid
+ var clientTwoCert = new ClientCertificateRequest(CLIENT_CN_2, false);
+ certRequest.withClientRequests(clientOneCert, clientTwoCert);
+ });
+
+ // now we expect opposite from what we tested in step one: client 1 must fail and client 2 must succeed
+ AwaitilityUtils.untilAsserted(() -> {
+ var httpResponse = app.mutinyHttps(CLIENT_CN_2).get("/management-ping").sendAndAwait();
+ assertEquals("pong", httpResponse.bodyAsString());
+ assertEquals(HttpStatus.SC_OK, httpResponse.statusCode());
+
+ callManagementPingRouteAndExpectFailure(CLIENT_CN_1);
+ });
+ }
+
+ private static void callManagementPingRouteAndExpectFailure(String clientCn) {
+ // this client certs are not in the server truststore, therefore they cannot be trusted
+ try {
+ app.mutinyHttps(clientCn).get("/management-ping").sendAndAwait();
+ // this must never happen, basically as SSL handshake must throw exception
+ Assertions.fail("SSL handshake didn't fail even though certificate host is unknown");
+ } catch (Exception e) {
+ // failure is expected
+ assertTrue(e.getMessage().contains("Received fatal alert: bad_certificate"),
+ "Expected failure over bad certificate, but got: " + e.getMessage());
+ }
+ }
+}
diff --git a/http/rest-client-reactive/src/main/java/io/quarkus/ts/http/restclient/reactive/fault/tolerance/HeaderResource.java b/http/rest-client-reactive/src/main/java/io/quarkus/ts/http/restclient/reactive/fault/tolerance/HeaderResource.java
new file mode 100644
index 000000000..20baaa6df
--- /dev/null
+++ b/http/rest-client-reactive/src/main/java/io/quarkus/ts/http/restclient/reactive/fault/tolerance/HeaderResource.java
@@ -0,0 +1,37 @@
+package io.quarkus.ts.http.restclient.reactive.fault.tolerance;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.MultivaluedMap;
+import jakarta.ws.rs.core.Response;
+
+/**
+ * Stores request headers from incoming server requests
+ * and exposes an endpoint that returns these headers
+ * It is used for testing purposes to verify if headers are correctly propagated.
+ */
+@Path("/fault/headers")
+@ApplicationScoped
+public class HeaderResource {
+
+ private final List