-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- replace resteasy endpoints by reactiveRoutes - add opentelemetry and opentracing dependencies - add opentelemetry test case
- Loading branch information
pablo gonzalez granados
committed
Apr 14, 2021
1 parent
eb57207
commit b60761e
Showing
13 changed files
with
230 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 0 additions & 21 deletions
21
...t/src/main/java/io/quarkus/qe/vertx/webclient/exceptions/ApplicationExceptionHandler.java
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
...s-vertx-webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/FailureHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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()))); | ||
} | ||
} | ||
} |
12 changes: 12 additions & 0 deletions
12
...webClient/src/main/java/io/quarkus/qe/vertx/webclient/handler/TracingExampleResource.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package io.quarkus.qe.vertx.webclient.handler; | ||
|
||
import io.quarkus.vertx.web.Route; | ||
import io.quarkus.vertx.web.RouteBase; | ||
|
||
@RouteBase(path = "/trace") | ||
public class TracingExampleResource { | ||
@Route(methods = Route.HttpMethod.GET, path = "/hello") | ||
boolean validateRequestSinglePara() { | ||
return true; | ||
} | ||
} |
2 changes: 1 addition & 1 deletion
2
...a/io/quarkus/qe/vertx/webclient/Joke.java → ...uarkus/qe/vertx/webclient/model/Joke.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
6 changes: 5 additions & 1 deletion
6
300-quarkus-vertx-webClient/src/main/resources/application.properties
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
vertx.webclient.retries=3 | ||
|
||
# Jaeger | ||
quarkus.opentelemetry.tracer.exporter.jaeger.endpoint=http://localhost:14250/api/traces |
133 changes: 83 additions & 50 deletions
133
...-vertx-webClient/src/test/java/io/quarkus/qe/vertx/webclient/ChuckNorrisResourceTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,94 +1,127 @@ | ||
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 java.net.HttpURLConnection; | ||
import java.time.Duration; | ||
import java.util.List; | ||
import java.util.concurrent.TimeUnit; | ||
import org.apache.http.HttpStatus; | ||
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.hasSize; | ||
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 { | ||
|
||
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 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); | ||
|
||
@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)))); | ||
|
||
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/hello"; | ||
await().atMost(1, TimeUnit.MINUTES).pollInterval(Duration.ofSeconds(1)).untilAsserted(() -> { | ||
given().when() | ||
.get("/trace/hello") | ||
.then() | ||
.statusCode(HttpStatus.SC_OK); | ||
|
||
List<String> operationNames = given().when() | ||
.queryParam("limit", pageLimit) | ||
.queryParam("lookback", "1h") | ||
.queryParam("service", getServiceName()) | ||
.queryParam("operation", expectedOperationName) | ||
.get(jaegerEndpoint) | ||
.then() | ||
.statusCode(HttpStatus.SC_OK) | ||
.body("data.size()", greaterThan(0)) | ||
.body("data.spans", hasSize(greaterThan(0))) | ||
.body("data.spans.tags", hasSize(greaterThan(0))) | ||
.body("data.spans.operationName", not(empty())) | ||
.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(){ | ||
return (IS_NATIVE)?"300-quarkus-vertx-webclient":"<<unset>>".toLowerCase(); | ||
} | ||
} |
Oops, something went wrong.