Skip to content

Commit

Permalink
Parameter and error tests (#113)
Browse files Browse the repository at this point in the history
* tck changes

* JAX-RS TCK test fixes

- Code review comments
- Change expected response code to Bad Request (400) so that we can
  distinguish between the expected error code and an error code
  generated by an unexpected exception

* Add parameters to MpRestClientAsyncTest

* Correct assertEquals arguments wrong way round

---------

Co-authored-by: Andrew Rouse <anrouse@uk.ibm.com>
  • Loading branch information
yasmin-aumeeruddy and Azquelt committed Aug 11, 2023
1 parent a391bcf commit bf4acd3
Show file tree
Hide file tree
Showing 8 changed files with 416 additions and 43 deletions.
Expand Up @@ -25,6 +25,7 @@
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_STATUS_CODE;
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_TARGET;
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_URL;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.net.HttpURLConnection.HTTP_OK;

import java.net.URL;
Expand All @@ -49,7 +50,6 @@
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.trace.data.SpanData;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.HttpMethod;

public class JaxRsClientAsyncTest extends Arquillian {
Expand Down Expand Up @@ -77,6 +77,7 @@ public static WebArchive createDeployment() {
URL url;

public static final String TEST_PASSED = "Test Passed";
public static final String QUERY_VALUE = "bar";

@Inject
private InMemorySpanExporter spanExporter;
Expand All @@ -92,16 +93,65 @@ void setUp() {

@Test
public void testIntegrationWithJaxRsClient() throws Exception {
basicClient.get("/JaxRsClientAsyncTestEndpoint/jaxrsclient");
basicClient.get("/JaxRsClientAsyncTestEndpoint/jaxrsclient?baggageValue=" + QUERY_VALUE);
readSpans();
}

@Test
public void testIntegrationWithJaxRsClientAsync() throws Exception {
basicClient.get("/JaxRsClientAsyncTestEndpoint/jaxrsclientasync");
basicClient.get("/JaxRsClientAsyncTestEndpoint/jaxrsclientasync?baggageValue=" + QUERY_VALUE);
readSpans();
}

@Test
public void testIntegrationWithJaxRsClientError() throws Exception {
basicClient.get("/JaxRsClientAsyncTestEndpoint/jaxrsclienterror");
readErrorSpans();
}

public void readErrorSpans() {

List<SpanData> spanData = spanExporter.getFinishedSpanItems(3);

List<SpanData> serverSpans = spanExporter.getSpansWithKind(SpanKind.SERVER);

SpanData firstURL = null;
SpanData secondURL = null;
for (SpanData span : serverSpans) {
if (span.getAttributes().get(HTTP_TARGET).contains("JaxRsClientAsyncTestEndpoint/jaxrsclient")) {
firstURL = span;
} else {
secondURL = span;
}
}

Assert.assertNotNull(firstURL);
Assert.assertNotNull(secondURL);

SpanData httpGet = spanExporter.getFirst(SpanKind.CLIENT);

// Assert correct parent-child links
// Shows that propagation occurred
Assert.assertEquals(httpGet.getSpanId(), secondURL.getParentSpanId());
Assert.assertEquals(firstURL.getSpanId(), httpGet.getParentSpanId());

Assert.assertEquals(firstURL.getAttributes().get(HTTP_METHOD), HttpMethod.GET);
Assert.assertEquals(firstURL.getAttributes().get(HTTP_SCHEME), "http");

// getError returns an internal server error...
Assert.assertEquals(secondURL.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_BAD_REQUEST);
// Which gets received by the client
Assert.assertEquals(httpGet.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_BAD_REQUEST);
// The exception from the client is inspected and handled so this method should return OK
Assert.assertEquals(firstURL.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_OK);

// There are many different URLs that will end up here. But all should contain "JaxRsClientAsyncTestEndpoint"
Assert.assertTrue(httpGet.getAttributes().get(HTTP_URL).contains("JaxRsClientAsyncTestEndpoint"));

Assert.assertEquals(httpGet.getAttributes().get(HTTP_METHOD), HttpMethod.GET);
Assert.assertTrue(httpGet.getAttributes().get(HTTP_URL).contains("JaxRsClientAsyncTestEndpoint"));
}

public void readSpans() {

List<SpanData> spanData = spanExporter.getFinishedSpanItems(3);
Expand All @@ -128,15 +178,16 @@ public void readSpans() {
Assert.assertEquals(httpGet.getSpanId(), secondURL.getParentSpanId());
Assert.assertEquals(firstURL.getSpanId(), httpGet.getParentSpanId());

Assert.assertEquals(HTTP_OK, firstURL.getAttributes().get(HTTP_STATUS_CODE).intValue());
Assert.assertEquals(HttpMethod.GET, firstURL.getAttributes().get(HTTP_METHOD));
Assert.assertEquals("http", firstURL.getAttributes().get(HTTP_SCHEME));
Assert.assertEquals(firstURL.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_OK);
Assert.assertEquals(firstURL.getAttributes().get(HTTP_METHOD), HttpMethod.GET);
Assert.assertEquals(firstURL.getAttributes().get(HTTP_SCHEME), "http");
Assert.assertTrue(firstURL.getAttributes().get(HTTP_TARGET).contains(QUERY_VALUE));

// There are many different URLs that will end up here. But all should contain "JaxRsClientAsyncTestEndpoint"
Assert.assertTrue(httpGet.getAttributes().get(HTTP_URL).contains("JaxRsClientAsyncTestEndpoint"));

Assert.assertEquals(HTTP_OK, httpGet.getAttributes().get(HTTP_STATUS_CODE).intValue());
Assert.assertEquals(HttpMethod.GET, httpGet.getAttributes().get(HTTP_METHOD));
Assert.assertEquals(httpGet.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_OK);
Assert.assertEquals(httpGet.getAttributes().get(HTTP_METHOD), HttpMethod.GET);
Assert.assertTrue(httpGet.getAttributes().get(HTTP_URL).contains("JaxRsClientAsyncTestEndpoint"));
}
}
Expand Up @@ -19,8 +19,12 @@
*/
package org.eclipse.microprofile.telemetry.tracing.tck.async;

import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.eclipse.microprofile.telemetry.tracing.tck.exporter.InMemorySpanExporter;
Expand All @@ -35,6 +39,8 @@
import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Application;
Expand Down Expand Up @@ -69,21 +75,22 @@ private void closeClient() {

@GET
@Path("/jaxrsclient")
public Response getJax(@Context UriInfo uriInfo) {
public Response getJax(@Context UriInfo uriInfo, @QueryParam(value = "baggageValue") String baggageValue) {
Assert.assertNotNull(Span.current());

try (Scope s = Baggage.builder().put("foo", "bar").build().makeCurrent()) {
try (Scope s = Baggage.builder().put("foo", baggageValue).build().makeCurrent()) {
Baggage baggage = Baggage.current();
Assert.assertEquals("bar", baggage.getEntryValue("foo"));
Assert.assertEquals(baggage.getEntryValue("foo"), baggageValue);

String url = new String(uriInfo.getAbsolutePath().toString());
url = url.replace("jaxrsclient", "jaxrstwo"); // The jaxrsclient will use the URL as given so it needs
// the final part to be provided.
// Use our own URL to work out the URL of the other test endpoint
url = url.replace("jaxrsclient", "jaxrstwo");

String result = client.target(url)
.queryParam("baggageValue", baggageValue)
.request(MediaType.TEXT_PLAIN)
.get(String.class);
Assert.assertEquals(TEST_PASSED, result);
Assert.assertEquals(result, TEST_PASSED);
} finally {
client.close();
}
Expand All @@ -92,25 +99,26 @@ public Response getJax(@Context UriInfo uriInfo) {

@GET
@Path("/jaxrsclientasync")
public Response getJaxAsync(@Context UriInfo uriInfo) {
public Response getJaxAsync(@Context UriInfo uriInfo, @QueryParam(value = "baggageValue") String baggageValue) {
Assert.assertNotNull(Span.current());

try (Scope s = Baggage.builder().put("foo", "bar").build().makeCurrent()) {
try (Scope s = Baggage.builder().put("foo", baggageValue).build().makeCurrent()) {
Baggage baggage = Baggage.current();
Assert.assertEquals("bar", baggage.getEntryValue("foo"));
Assert.assertEquals(baggage.getEntryValue("foo"), baggageValue);

String url = new String(uriInfo.getAbsolutePath().toString());
url = url.replace("jaxrsclientasync", "jaxrstwo"); // The jaxrsclient will use the URL as given so it needs
// the final part to be provided.
// Use our own URL to work out the URL of the other test endpoint
url = url.replace("jaxrsclientasync", "jaxrstwo");

Client client = ClientBuilder.newClient();
Future<String> result = client.target(url)
.queryParam("baggageValue", baggageValue)
.request(MediaType.TEXT_PLAIN)
.async()
.get(String.class);
try {
String resultValue = result.get(10, SECONDS);
Assert.assertEquals(TEST_PASSED, resultValue);
Assert.assertEquals(resultValue, TEST_PASSED);
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Expand All @@ -120,16 +128,57 @@ public Response getJaxAsync(@Context UriInfo uriInfo) {
return Response.ok(Span.current().getSpanContext().getTraceId()).build();
}

@GET
@Path("/jaxrsclienterror")
public Response getJaxError(@Context UriInfo uriInfo, @QueryParam(value = "baggageValue") String baggageValue) {
Assert.assertNotNull(Span.current());

try (Scope s = Baggage.builder().put("foo", baggageValue).build().makeCurrent()) {
Baggage baggage = Baggage.current();
Assert.assertEquals(baggage.getEntryValue("foo"), baggageValue);

String url = new String(uriInfo.getAbsolutePath().toString());
// Use our own URL to work out the URL of the other test endpoint
url = url.replace("jaxrsclienterror", "error");

Client client = ClientBuilder.newClient();
Future<String> result = client.target(url)
.request(MediaType.TEXT_PLAIN)
.async()
.get(String.class);
try {
result.get(10, SECONDS);
fail("Client didn't throw an exception");
} catch (ExecutionException e) {
// Expected because server returned BAD_REQUEST
WebApplicationException webEx = (WebApplicationException) e.getCause();
assertEquals(webEx.getResponse().getStatus(), HTTP_BAD_REQUEST);
} catch (Exception e) {
// Wrap and throw unexpected exceptions
throw new RuntimeException(e);
} finally {
client.close();
}
}
return Response.ok(Span.current().getSpanContext().getTraceId()).build();
}

// A method to be called by JAX Clients
// This method triggers span creation and span propagation is automatic.
@GET
@Path("/jaxrstwo")
public Response getJaxRsTwo() {
public Response getJaxRsTwo(@QueryParam(value = "baggageValue") String baggageValue) {
Assert.assertNotNull(Span.current());
Baggage baggage = Baggage.current();
// Assert that Baggage is propagated from Jax Server to Jax Client
Assert.assertEquals("bar", baggage.getEntryValue("foo"));
Assert.assertEquals(baggage.getEntryValue("foo"), baggageValue);
return Response.ok(TEST_PASSED).build();
}

@GET
@Path("/error")
public Response getError() {
return Response.status(HTTP_BAD_REQUEST).build();
}

}
Expand Up @@ -20,9 +20,14 @@

package org.eclipse.microprofile.telemetry.tracing.tck.async;

import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_STATUS_CODE;
import static io.opentelemetry.semconv.trace.attributes.SemanticAttributes.HTTP_TARGET;
import static java.net.HttpURLConnection.HTTP_BAD_REQUEST;
import static org.eclipse.microprofile.telemetry.tracing.tck.async.JaxRsServerAsyncTestEndpoint.BAGGAGE_VALUE_ATTR;
import static org.testng.Assert.assertEquals;
import static org.testng.Assert.fail;

import java.net.HttpURLConnection;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
Expand All @@ -49,6 +54,7 @@
import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider;
import io.opentelemetry.sdk.trace.data.SpanData;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;

class JaxRsServerAsyncTest extends Arquillian {

Expand All @@ -70,6 +76,7 @@ public static WebArchive createDeployment() {
}

private static final String TEST_VALUE = "test.value";
public static final String QUERY_VALUE = "bar";

@Inject
private InMemorySpanExporter spanExporter;
Expand All @@ -87,12 +94,22 @@ void setUp() {

@Test(groups = "optional-jaxrs-tests")
public void testJaxRsServerAsyncCompletionStage() {
doAsyncTest(JaxRsServerAsyncTestEndpointClient::getCompletionStage);
doAsyncTest((client) -> client.getCompletionStage(QUERY_VALUE));
}

@Test(groups = "optional-jaxrs-tests")
public void testJaxRsServerAsyncCompletionStageError() {
doErrorAsyncTest((client) -> client.getCompletionStageError(QUERY_VALUE));
}

@Test(groups = "optional-jaxrs-tests")
public void testJaxRsServerAsyncSuspend() {
doAsyncTest(JaxRsServerAsyncTestEndpointClient::getSuspend);
doAsyncTest((client) -> client.getSuspend(QUERY_VALUE));
}

@Test(groups = "optional-jaxrs-tests")
public void testJaxRsServerAsyncSuspendError() {
doErrorAsyncTest((client) -> client.getSuspendError(QUERY_VALUE));
}

private void doAsyncTest(Function<JaxRsServerAsyncTestEndpointClient, String> requestFunction) {
Expand All @@ -106,9 +123,8 @@ private void doAsyncTest(Function<JaxRsServerAsyncTestEndpointClient, String> re
JaxRsServerAsyncTestEndpointClient client = RestClientBuilder.newBuilder()
.baseUri(url.toURI())
.build(JaxRsServerAsyncTestEndpointClient.class);

String response = requestFunction.apply(client);
Assert.assertEquals("OK", response);
Assert.assertEquals(response, "OK");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
Expand All @@ -131,6 +147,64 @@ private void doAsyncTest(Function<JaxRsServerAsyncTestEndpointClient, String> re
// Assert baggage propagated on subtask span
Assert.assertTrue(subtaskSpan.getAttributes().get(BAGGAGE_VALUE_ATTR).contains(TEST_VALUE));

// Assert that query parameter was passed correctly
Assert.assertTrue(serverSpan.getAttributes().get(HTTP_TARGET).contains(QUERY_VALUE));

// Assert that the server span finished after the subtask span
// Even though the resource method returned quickly, the span should not end until the response is actually
// returned
Assert.assertTrue(serverSpan.getEndEpochNanos() >= subtaskSpan.getEndEpochNanos());
}

private void doErrorAsyncTest(Function<JaxRsServerAsyncTestEndpointClient, String> requestFunction) {
Baggage baggage = Baggage.builder()
.put(JaxRsServerAsyncTestEndpoint.BAGGAGE_KEY, TEST_VALUE)
.build();

try (Scope s = baggage.makeCurrent()) {
// Make the request to the test endpoint
try {
JaxRsServerAsyncTestEndpointClient client = RestClientBuilder.newBuilder()
.baseUri(url.toURI())
.build(JaxRsServerAsyncTestEndpointClient.class);
try {
requestFunction.apply(client);
fail("Client did not throw an exception");
} catch (WebApplicationException e) {
assertEquals(e.getResponse().getStatus(), HttpURLConnection.HTTP_BAD_REQUEST);
readErrorSpans();
}
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
}

private void readErrorSpans() {
List<SpanData> spanData = spanExporter.getFinishedSpanItems(3);

SpanData subtaskSpan = spanExporter.getFirst(SpanKind.INTERNAL);
SpanData clientSpan = spanExporter.getFirst(SpanKind.CLIENT);
SpanData serverSpan = spanExporter.getFirst(SpanKind.SERVER);

// Assert correct parent-child links
// Shows that propagation occurred
assertEquals(serverSpan.getSpanId(), subtaskSpan.getParentSpanId());
assertEquals(clientSpan.getSpanId(), serverSpan.getParentSpanId());

// Assert the status code for the client and server spans
assertEquals(serverSpan.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_BAD_REQUEST);
assertEquals(clientSpan.getAttributes().get(HTTP_STATUS_CODE).intValue(), HTTP_BAD_REQUEST);

// Assert that the expected headers were used
Assert.assertTrue(serverSpan.getAttributes().get(BAGGAGE_VALUE_ATTR).contains(TEST_VALUE));

// Assert baggage propagated on subtask span
Assert.assertTrue(subtaskSpan.getAttributes().get(BAGGAGE_VALUE_ATTR).contains(TEST_VALUE));

// Assert that query parameter was passed correctly
Assert.assertTrue(serverSpan.getAttributes().get(HTTP_TARGET).contains(QUERY_VALUE));

// Assert that the server span finished after the subtask span
// Even though the resource method returned quickly, the span should not end until the response is actually
// returned
Expand Down

0 comments on commit bf4acd3

Please sign in to comment.