diff --git a/300-quarkus-vertx-webClient/pom.xml b/300-quarkus-vertx-webClient/pom.xml
index 7cd2b467..e25c31ca 100644
--- a/300-quarkus-vertx-webClient/pom.xml
+++ b/300-quarkus-vertx-webClient/pom.xml
@@ -14,11 +14,11 @@
io.quarkus
- quarkus-resteasy
+ quarkus-opentelemetry
io.quarkus
- quarkus-resteasy-mutiny
+ quarkus-opentelemetry-exporter-jaeger
io.quarkus
@@ -32,13 +32,25 @@
io.smallrye.reactive
smallrye-mutiny-vertx-web-client
-
- io.quarkus
- quarkus-resteasy-jsonb
-
com.github.tomakehurst
wiremock-jre8
+ test
+
+
+ org.awaitility
+ awaitility
+ test
+
+
+ org.testcontainers
+ testcontainers
+ test
+
+
+ io.quarkus
+ quarkus-junit5-internal
+ test
\ No newline at end of file
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/exceptions/ApplicationExceptionHandler.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/exceptions/ApplicationExceptionHandler.java
deleted file mode 100644
index 6a2e05f3..00000000
--- a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/exceptions/ApplicationExceptionHandler.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package io.quarkus.qe.vertx.webclient.exceptions;
-
-import io.smallrye.mutiny.TimeoutException;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-@Provider
-public class ApplicationExceptionHandler implements ExceptionMapper {
- @Override
- public Response toResponse(RuntimeException e) {
-
- Response error = Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(e.getMessage()).build();
-
- if(e instanceof TimeoutException)
- error = Response.status(Response.Status.REQUEST_TIMEOUT).entity(e.getMessage()).build();
-
- return error;
- }
-}
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResource.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/ChuckNorrisResource.java
similarity index 63%
rename from 300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResource.java
rename to 300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/ChuckNorrisResource.java
index afd613b7..3099561c 100644
--- a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResource.java
+++ b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/ChuckNorrisResource.java
@@ -1,28 +1,31 @@
-package io.quarkus.qe.vertx.webclient;
+package io.quarkus.qe.vertx.webclient.handler;
+
+import static io.quarkus.vertx.web.Route.HttpMethod;
+
+import java.net.HttpURLConnection;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.List;
+import java.util.function.BiFunction;
+
+import javax.annotation.PostConstruct;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
import io.quarkus.qe.vertx.webclient.config.ChuckEndpointValue;
import io.quarkus.qe.vertx.webclient.config.VertxWebClientConfig;
+import io.quarkus.qe.vertx.webclient.model.Joke;
+import io.quarkus.vertx.web.Route;
+import io.quarkus.vertx.web.RouteBase;
import io.smallrye.mutiny.Uni;
-import io.vertx.core.json.Json;
import io.vertx.mutiny.core.Vertx;
+import io.vertx.mutiny.ext.web.client.HttpResponse;
import io.vertx.mutiny.ext.web.client.WebClient;
import io.vertx.mutiny.ext.web.client.predicate.ResponsePredicate;
import io.vertx.mutiny.ext.web.codec.BodyCodec;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import javax.annotation.PostConstruct;
-import javax.inject.Inject;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
-import javax.ws.rs.core.MediaType;
-import javax.ws.rs.core.Response;
-import java.time.Duration;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.BiFunction;
-
-@Path("/chuck")
+@RouteBase(path = "/chuck")
public class ChuckNorrisResource {
@Inject
@@ -41,51 +44,46 @@ void initialize() {
this.client = WebClient.create(vertx);
}
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/")
- public Uni getRandomJoke() {
+ @Route(methods = HttpMethod.GET, path = "/")
+ public Uni getRandomJoke() {
return getChuckQuoteAsJoke()
- .map(resp -> Response.ok(resp).build())
.ifNoItem().after(Duration.ofSeconds(httpClientConf.timeout)).fail()
.onFailure().retry().atMost(httpClientConf.retries);
}
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/bodyCodec")
- public Uni getRandomJokeWithBodyCodec() {
- return client.getAbs(chuckNorrisQuote.getValue())
+ @Route(methods = HttpMethod.GET, path = "/bodyCodec", produces = "application/json")
+ public Uni getRandomJokeWithBodyCodec() {
+ return client.getAbs(chuckNorrisQuote.getValue())
.as(BodyCodec.json(Joke.class))
.putHeader("Accept", "application/json")
- .expect(ResponsePredicate.status(Response.Status.OK.getStatusCode()))
+ .expect(ResponsePredicate.status(HttpURLConnection.HTTP_OK))
.send()
- .map(resp -> Response.ok(resp.body()).build())
+ .map(HttpResponse::body)
.ifNoItem().after(Duration.ofSeconds(httpClientConf.timeout)).fail()
.onFailure().retry().atMost(httpClientConf.retries);
}
- @GET
- @Produces(MediaType.APPLICATION_JSON)
- @Path("/combine")
- public Uni getTwoRandomJokes() {
+ @Route(methods = HttpMethod.GET, path = "/combine", produces = "application/json")
+ public Uni> getTwoRandomJokes() {
Uni jokeOne = getChuckQuoteAsJoke();
Uni jokeTwo = getChuckQuoteAsJoke();
return Uni.combine()
.all()
.unis(jokeOne, jokeTwo)
- .combinedWith((BiFunction>) Arrays::asList)
- .map(resp -> Response.ok(Json.encode(resp)).build());
+ .combinedWith((BiFunction>) Arrays::asList);
+ }
+
+ @Route(methods = HttpMethod.GET, path = "/pong", produces = "application/json")
+ public Uni ping() {
+ return Uni.createFrom().item("pong");
}
private Uni getChuckQuoteAsJoke() {
return client.getAbs(chuckNorrisQuote.getValue())
.putHeader("Accept", "application/json")
- .expect(ResponsePredicate.status(Response.Status.OK.getStatusCode()))
+ .expect(ResponsePredicate.status(HttpURLConnection.HTTP_OK))
.send()
.map(resp -> resp.bodyAsJsonObject().mapTo(Joke.class));
}
-
}
-
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/FailureHandler.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/FailureHandler.java
new file mode 100644
index 00000000..a7816951
--- /dev/null
+++ b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/FailureHandler.java
@@ -0,0 +1,21 @@
+package io.quarkus.qe.vertx.webclient.handler;
+
+import io.quarkus.vertx.web.Route;
+import io.smallrye.mutiny.TimeoutException;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.core.json.Json;
+import io.vertx.core.json.JsonObject;
+import java.net.HttpURLConnection;
+import javax.enterprise.context.ApplicationScoped;
+
+@ApplicationScoped
+public class FailureHandler {
+ @Route(path = "/*", type = Route.HandlerType.FAILURE, produces = "application/json")
+ void runtimeFailures(RuntimeException e, HttpServerResponse response) {
+ if(e instanceof TimeoutException){
+ response.setStatusCode(HttpURLConnection.HTTP_CLIENT_TIMEOUT).end(Json.encode(new JsonObject().put("msg", e.getMessage())));
+ }else{
+ response.setStatusCode(HttpURLConnection.HTTP_INTERNAL_ERROR).end(Json.encode(new JsonObject().put("msg", e.getMessage())));
+ }
+ }
+}
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/TracingExampleResource.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/TracingExampleResource.java
new file mode 100644
index 00000000..f965e154
--- /dev/null
+++ b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/TracingExampleResource.java
@@ -0,0 +1,20 @@
+package io.quarkus.qe.vertx.webclient.handler;
+
+import javax.inject.Inject;
+
+import io.quarkus.qe.vertx.webclient.service.PongService;
+import io.quarkus.vertx.web.Route;
+import io.quarkus.vertx.web.RouteBase;
+import io.smallrye.mutiny.Uni;
+
+@RouteBase(path = "/trace")
+public class TracingExampleResource {
+
+ @Inject
+ PongService pongService;
+
+ @Route(methods = Route.HttpMethod.GET, path = "/ping")
+ Uni pingRequest() {
+ return pongService.pong().onItem().transform(pong -> "ping-" + pong);
+ }
+}
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/Joke.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/model/Joke.java
similarity index 94%
rename from 300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/Joke.java
rename to 300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/model/Joke.java
index 4b37eea4..207f03a1 100644
--- a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/Joke.java
+++ b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/model/Joke.java
@@ -1,4 +1,4 @@
-package io.quarkus.qe.vertx.webclient;
+package io.quarkus.qe.vertx.webclient.model;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
diff --git a/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/service/PongService.java b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/service/PongService.java
new file mode 100644
index 00000000..7647af7f
--- /dev/null
+++ b/300-quarkus-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/service/PongService.java
@@ -0,0 +1,42 @@
+package io.quarkus.qe.vertx.webclient.service;
+
+import java.net.HttpURLConnection;
+
+import javax.annotation.PostConstruct;
+import javax.enterprise.context.ApplicationScoped;
+import javax.inject.Inject;
+
+import org.eclipse.microprofile.config.inject.ConfigProperty;
+
+import io.smallrye.mutiny.Uni;
+import io.vertx.mutiny.core.Vertx;
+import io.vertx.mutiny.ext.web.client.HttpResponse;
+import io.vertx.mutiny.ext.web.client.WebClient;
+import io.vertx.mutiny.ext.web.client.predicate.ResponsePredicate;
+
+@ApplicationScoped
+public class PongService {
+
+ @Inject
+ Vertx vertx;
+
+ @ConfigProperty(name = "quarkus.http.port")
+ public int port;
+
+ private WebClient client;
+ private String basePath;
+
+ @PostConstruct
+ void initialize() {
+ this.client = WebClient.create(vertx);
+ this.basePath = "http://localhost:" + port;
+ }
+
+ public Uni pong() {
+ return client.getAbs(basePath + "/chuck/pong")
+ .putHeader("Accept", "application/json")
+ .expect(ResponsePredicate.status(HttpURLConnection.HTTP_OK))
+ .send()
+ .map(HttpResponse::bodyAsString);
+ }
+}
diff --git a/300-quarkus-vertx-webClient/src/main/resources/application.properties b/300-quarkus-vertx-webClient/src/main/resources/application.properties
index 51bc68d4..cd9938f9 100644
--- a/300-quarkus-vertx-webClient/src/main/resources/application.properties
+++ b/300-quarkus-vertx-webClient/src/main/resources/application.properties
@@ -1,4 +1,8 @@
# Configuration file
+quarkus.http.port=8081
chucknorris.api.domain=https://api.chucknorris.io
vertx.webclient.timeout-sec=2
-vertx.webclient.retries=3
\ No newline at end of file
+vertx.webclient.retries=3
+
+# Jaeger
+quarkus.opentelemetry.tracer.exporter.jaeger.endpoint=http://localhost:14250/api/traces
\ No newline at end of file
diff --git a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResourceTest.java b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResourceTest.java
index ee53c594..d3cf9da9 100644
--- a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResourceTest.java
+++ b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResourceTest.java
@@ -1,94 +1,178 @@
package io.quarkus.qe.vertx.webclient;
+import io.quarkus.qe.vertx.webclient.resources.JaegerTestResource;
+import io.quarkus.qe.vertx.webclient.resources.WireMockChuckNorrisResource;
import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
+import io.restassured.response.Response;
+import java.net.HttpURLConnection;
+import java.time.Duration;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+import org.apache.http.HttpStatus;
+import org.hamcrest.Matcher;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
-import javax.ws.rs.core.Response;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
import static io.restassured.RestAssured.given;
+import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.containsStringIgnoringCase;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.empty;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.core.Every.everyItem;
+import static org.hamcrest.core.StringContains.containsString;
@QuarkusTest
@QuarkusTestResource(WireMockChuckNorrisResource.class)
+@QuarkusTestResource(JaegerTestResource.class)
public class ChuckNorrisResourceTest {
+ private final static String jaegerEndpoint = "http://localhost:16686/api/traces";
+ static final String EXPECTED_ID = "aBanNLDwR-SAz7iMHuCiyw";
+ static final String EXPECTED_VALUE = "Chuck Norris has already been to mars; that why there's no signs of life";
+ static final int DELAY = 3500; // must be greater than vertx.webclient.timeout-sec
+ static final String QUARKUS_PROFILE = "quarkus.profile";
+ static final String NATIVE = "native";
+ static final boolean IS_NATIVE = System.getProperty(QUARKUS_PROFILE, "").equals(NATIVE);
- final static String EXPECTED_ID = "aBanNLDwR-SAz7iMHuCiyw";
- final static String EXPECTED_VALUE = "Chuck Norris has already been to mars; that why there's no signs of life";
+ private Response resp;
@Test
@DisplayName("Vert.x WebClient [flavor: mutiny] -> Map json response body to POJO")
- public void getChuckJokeAsJSON(){
-
- stubFor(get(urlEqualTo("/jokes/random"))
- .willReturn(aResponse()
- .withHeader("Accept", "application/json")
- .withBody(String.format("{\"categories\":[]," +
- "\"created_at\":\"2020-01-05 13:42:19.576875\"," +
- "\"icon_url\":\"https://assets.chucknorris.host/img/avatar/chuck-norris.png\"," +
- "\"id\":\"%s\"," +
- "\"updated_at\":\"2020-01-05 13:42:19.576875\"," +
- "\"url\":\"https://api.chucknorris.io/jokes/sC09X1xQQymE4SciIjyV0g\"," +
- "\"value\":\"%s\"}", EXPECTED_ID, EXPECTED_VALUE))));
-
+ public void getChuckJokeAsJSON() {
+ setupMockHttpServer();
given()
.when()
- .get("/chuck")
+ .get("/chuck/")
.then()
- .statusCode(Response.Status.OK.getStatusCode())
- .body(containsStringIgnoringCase((String.format("{\"id\":\"%s\",\"jokeText\":\"%s\"}", EXPECTED_ID, EXPECTED_VALUE))));
+ .statusCode(HttpURLConnection.HTTP_OK)
+ .body("id", containsStringIgnoringCase(EXPECTED_ID))
+ .body("value", containsStringIgnoringCase(EXPECTED_VALUE));
}
@Test
@DisplayName("Vert.x WebClient [flavor: mutiny] -> Mapped json response by 'as' mutiny method.")
public void getChuckJokeByJsonBodyCodec() throws InterruptedException {
+ setupMockHttpServer();
+ given()
+ .when()
+ .get("/chuck/bodyCodec/")
+ .then()
+ .statusCode(HttpURLConnection.HTTP_OK)
+ .body("id", containsStringIgnoringCase(EXPECTED_ID))
+ .body("value", containsStringIgnoringCase(EXPECTED_VALUE));
+ }
+ @Test
+ @DisplayName("Vert.x WebClient [flavor: mutiny] -> If third party server exceed http client timeout, then throw a timeout exception.")
+ public void getTimeoutWhenResponseItsTooSlow() {
stubFor(get(urlEqualTo("/jokes/random"))
.willReturn(aResponse()
.withHeader("Accept", "application/json")
- .withBody(String.format("{\"categories\":[]," +
- "\"created_at\":\"2020-01-05 13:42:19.576875\"," +
- "\"icon_url\":\"https://assets.chucknorris.host/img/avatar/chuck-norris.png\"," +
- "\"id\":\"%s\"," +
- "\"updated_at\":\"2020-01-05 13:42:19.576875\"," +
- "\"url\":\"https://api.chucknorris.io/jokes/sC09X1xQQymE4SciIjyV0g\"," +
- "\"value\":\"%s\"}", EXPECTED_ID, EXPECTED_VALUE))));
+ .withFixedDelay(DELAY)));
given()
- .filter(
- (request, response, ctx) -> {
- io.restassured.response.Response resp = ctx.next(request, response);
- if (resp.statusCode() >= 400) {
- System.err.println(resp.body().prettyPrint());
- System.err.println(request.getMethod() + " " + request.getURI() + " => "
- + response.getStatusCode() + " " + response.getStatusLine());
- }
- return resp;
- })
.when()
- .get("/chuck/bodyCodec")
+ .get("/chuck/bodyCodec/")
.then()
- .statusCode(Response.Status.OK.getStatusCode())
- .body(containsStringIgnoringCase((String.format("{\"id\":\"%s\",\"jokeText\":\"%s\"}", EXPECTED_ID, EXPECTED_VALUE))));
+ .statusCode(HttpURLConnection.HTTP_CLIENT_TIMEOUT);
}
@Test
- @DisplayName("Vert.x WebClient [flavor: mutiny] -> If third party server exceed http client timeout, then throw a timeout exception.")
- public void getTimeoutWhenResponseItsTooSlow(){
- final int delay = 3500; // must be greater than vertx.webclient.timeout-sec
+ public void endpointShouldTrace() {
+ final int pageLimit = 50;
+ final String expectedOperationName = "trace/ping";
+ await().atMost(1, TimeUnit.MINUTES).pollInterval(Duration.ofSeconds(1)).untilAsserted(() -> {
+ whenIMakePingRequest();
+ thenRetrieveTraces(pageLimit, "1h", getServiceName(), expectedOperationName);
+ thenStatusCodeMustBe(HttpStatus.SC_OK);
+ thenTraceDataSizeMustBe(greaterThan(0));
+ thenTraceSpanSizeMustBe(greaterThan(0));
+ thenTraceSpanTagsSizeMustBe(greaterThan(0));
+ thenTraceSpansOperationNameMustBe(not(empty()));
+ thenCheckThatAllOperationNamesAreEqualTo(expectedOperationName);
+ });
+ }
+ @Test
+ @Disabled("https://github.com/quarkusio/quarkus/issues/16507")
+ public void httpClientShouldHaveHisOwnSpan() {
+ final int pageLimit = 50;
+ final String expectedOperationName = "trace/ping";
+ await().atMost(1, TimeUnit.MINUTES).pollInterval(Duration.ofSeconds(1)).untilAsserted(() -> {
+ whenIMakePingRequest();
+ thenRetrieveTraces(pageLimit, "1h", getServiceName(), expectedOperationName);
+ thenStatusCodeMustBe(HttpStatus.SC_OK);
+ thenTraceDataSizeMustBe(greaterThan(0));
+ thenTraceSpanSizeMustBe(greaterThan(1));
+ thenTraceSpanTagsSizeMustBe(greaterThan(0));
+ thenTraceSpansOperationNameMustBe(not(empty()));
+ thenCheckThatAllOperationNamesAreEqualTo(expectedOperationName);
+ });
+ }
+
+ private void whenIMakePingRequest() {
+ given().when()
+ .get("/trace/ping")
+ .then()
+ .statusCode(HttpStatus.SC_OK).body(containsStringIgnoringCase("ping-pong"));
+ }
+
+ private void thenRetrieveTraces(int pageLimit, String lookBack, String serviceName, String operationName) {
+ resp = given().when()
+ .queryParam("limit", pageLimit)
+ .queryParam("lookback", lookBack)
+ .queryParam("service", serviceName)
+ .queryParam("operation", operationName)
+ .get(jaegerEndpoint);
+ }
+
+ private void thenStatusCodeMustBe(int expectedStatusCode) {
+ resp.then().statusCode(expectedStatusCode);
+ }
+
+ private void thenTraceDataSizeMustBe(Matcher> matcher) {
+ resp.then().body("data.size()", matcher);
+ }
+
+ private void thenTraceSpanSizeMustBe(Matcher> matcher) {
+ resp.then().body("data[0].spans.size()", matcher);
+ }
+
+ private void thenTraceSpanTagsSizeMustBe(Matcher> matcher) {
+ resp.then().body("data[0].spans[0].tags.size()", matcher);
+ }
+
+ private void thenTraceSpansOperationNameMustBe(Matcher> matcher) {
+ resp.then().body("data.spans.operationName", matcher);
+ }
+
+ private void thenCheckThatAllOperationNamesAreEqualTo(String expectedOperationName) {
+ List operationNames = resp.then().extract().jsonPath().getList("data.spans.operationName", String.class);
+ assertThat(operationNames, everyItem(containsString(expectedOperationName)));
+ }
+
+ private void setupMockHttpServer() {
stubFor(get(urlEqualTo("/jokes/random"))
.willReturn(aResponse()
.withHeader("Accept", "application/json")
- .withFixedDelay(delay)));
+ .withBody(String.format("{\"categories\":[]," +
+ "\"created_at\":\"2020-01-05 13:42:19.576875\"," +
+ "\"icon_url\":\"https://assets.chucknorris.host/img/avatar/chuck-norris.png\"," +
+ "\"id\":\"%s\"," +
+ "\"updated_at\":\"2020-01-05 13:42:19.576875\"," +
+ "\"url\":\"https://api.chucknorris.io/jokes/sC09X1xQQymE4SciIjyV0g\"," +
+ "\"value\":\"%s\"}", EXPECTED_ID, EXPECTED_VALUE))));
+ }
- given()
- .when()
- .get("/chuck/bodyCodec")
- .then()
- .statusCode(Response.Status.REQUEST_TIMEOUT.getStatusCode());
+ private String getServiceName() {
+ // TODO https://github.com/quarkusio/quarkus/issues/16499
+ return (IS_NATIVE) ? "300-quarkus-vertx-webclient" : "<>";
}
}
diff --git a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerContainer.java b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerContainer.java
new file mode 100644
index 00000000..170d50ff
--- /dev/null
+++ b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerContainer.java
@@ -0,0 +1,19 @@
+package io.quarkus.qe.vertx.webclient.resources;
+
+import java.time.Duration;
+
+import org.testcontainers.containers.GenericContainer;
+
+public class JaegerContainer extends GenericContainer {
+ public static final int REST_PORT = 16686;
+ private static final int TRACE_PORT = 14250;
+
+ private static final int STARTUP_TIMEOUT = 30000;
+
+ public JaegerContainer() {
+ super("jaegertracing/all-in-one:latest");
+ withStartupTimeout(Duration.ofMillis(STARTUP_TIMEOUT));
+ addFixedExposedPort(REST_PORT, REST_PORT);
+ addFixedExposedPort(TRACE_PORT, TRACE_PORT);
+ }
+}
diff --git a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerTestResource.java b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerTestResource.java
new file mode 100644
index 00000000..3b50bcdc
--- /dev/null
+++ b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/JaegerTestResource.java
@@ -0,0 +1,27 @@
+package io.quarkus.qe.vertx.webclient.resources;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+import org.testcontainers.containers.GenericContainer;
+
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+
+public class JaegerTestResource implements QuarkusTestResourceLifecycleManager {
+
+ private GenericContainer> container;
+
+ @Override
+ public Map start() {
+ container = new JaegerContainer();
+ container.start();
+
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void stop() {
+ Optional.ofNullable(container).ifPresent(GenericContainer::stop);
+ }
+}
diff --git a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/WireMockChuckNorrisResource.java b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/WireMockChuckNorrisResource.java
similarity index 82%
rename from 300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/WireMockChuckNorrisResource.java
rename to 300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/WireMockChuckNorrisResource.java
index cbffa1f3..fd5cca92 100644
--- a/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/WireMockChuckNorrisResource.java
+++ b/300-quarkus-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/resources/WireMockChuckNorrisResource.java
@@ -1,26 +1,26 @@
-package io.quarkus.qe.vertx.webclient;
-
-import com.github.tomakehurst.wiremock.WireMockServer;
-import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+package io.quarkus.qe.vertx.webclient.resources;
import java.util.Collections;
import java.util.Map;
import java.util.Objects;
-public class WireMockChuckNorrisResource implements QuarkusTestResourceLifecycleManager {
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;
+
+public class WireMockChuckNorrisResource implements QuarkusTestResourceLifecycleManager {
private WireMockServer wireMockServer;
@Override
public Map start() {
wireMockServer = new WireMockServer();
wireMockServer.start();
-
return Collections.singletonMap("chucknorris.api.domain", wireMockServer.baseUrl());
}
@Override
public void stop() {
- if (Objects.nonNull(wireMockServer)) wireMockServer.stop();
+ if (Objects.nonNull(wireMockServer))
+ wireMockServer.stop();
}
}
diff --git a/300-quarkus-vertx-webClient/src/test/resources/application.properties b/300-quarkus-vertx-webClient/src/test/resources/application.properties
index bb6960a7..08385610 100644
--- a/300-quarkus-vertx-webClient/src/test/resources/application.properties
+++ b/300-quarkus-vertx-webClient/src/test/resources/application.properties
@@ -1,6 +1,10 @@
# Configuration file
quarkus.test.native-image-profile=test
+quarkus.http.port=8081
chucknorris.api.domain=https://api.chucknorris.io/
vertx.webclient.timeout-sec=1
-vertx.webclient.retries=1
\ No newline at end of file
+vertx.webclient.retries=1
+
+# Jaeger
+quarkus.opentelemetry.tracer.exporter.jaeger.endpoint=http://localhost:14250/api/traces
\ No newline at end of file
diff --git a/304-quarkus-vertx-routes/src/main/java/io/quarkus/qe/ReactiveRoutesTracing.java b/304-quarkus-vertx-routes/src/main/java/io/quarkus/qe/ReactiveRoutesTracing.java
new file mode 100644
index 00000000..0913ea35
--- /dev/null
+++ b/304-quarkus-vertx-routes/src/main/java/io/quarkus/qe/ReactiveRoutesTracing.java
@@ -0,0 +1,13 @@
+package io.quarkus.qe;
+
+import io.quarkus.vertx.web.Route;
+import io.quarkus.vertx.web.RouteBase;
+import io.vertx.ext.web.RoutingContext;
+
+@RouteBase(path = "/trace")
+public class ReactiveRoutesTracing {
+ @Route(methods = Route.HttpMethod.GET, path = "/hello")
+ boolean validateRequestSinglePara() {
+ return true;
+ }
+}