|  | 
|  | 1 | +/* | 
|  | 2 | + * Copyright The OpenTelemetry Authors | 
|  | 3 | + * SPDX-License-Identifier: Apache-2.0 | 
|  | 4 | + */ | 
|  | 5 | + | 
|  | 6 | +package io.opentelemetry.javaagent.instrumentation.avaje.jex.v3_0; | 
|  | 7 | + | 
|  | 8 | +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; | 
|  | 9 | +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.equalTo; | 
|  | 10 | +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; | 
|  | 11 | +import static io.opentelemetry.semconv.ClientAttributes.CLIENT_ADDRESS; | 
|  | 12 | +import static io.opentelemetry.semconv.ErrorAttributes.ERROR_TYPE; | 
|  | 13 | +import static io.opentelemetry.semconv.HttpAttributes.HTTP_REQUEST_METHOD; | 
|  | 14 | +import static io.opentelemetry.semconv.HttpAttributes.HTTP_RESPONSE_STATUS_CODE; | 
|  | 15 | +import static io.opentelemetry.semconv.HttpAttributes.HTTP_ROUTE; | 
|  | 16 | +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_ADDRESS; | 
|  | 17 | +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PEER_PORT; | 
|  | 18 | +import static io.opentelemetry.semconv.NetworkAttributes.NETWORK_PROTOCOL_VERSION; | 
|  | 19 | +import static io.opentelemetry.semconv.ServerAttributes.SERVER_ADDRESS; | 
|  | 20 | +import static io.opentelemetry.semconv.ServerAttributes.SERVER_PORT; | 
|  | 21 | +import static io.opentelemetry.semconv.UrlAttributes.URL_PATH; | 
|  | 22 | +import static io.opentelemetry.semconv.UrlAttributes.URL_SCHEME; | 
|  | 23 | +import static io.opentelemetry.semconv.UserAgentAttributes.USER_AGENT_ORIGINAL; | 
|  | 24 | +import static org.assertj.core.api.Assertions.assertThat; | 
|  | 25 | + | 
|  | 26 | +import io.avaje.jex.Jex.Server; | 
|  | 27 | +import io.opentelemetry.api.trace.SpanKind; | 
|  | 28 | +import io.opentelemetry.instrumentation.testing.junit.AgentInstrumentationExtension; | 
|  | 29 | +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; | 
|  | 30 | +import io.opentelemetry.testing.internal.armeria.client.WebClient; | 
|  | 31 | +import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; | 
|  | 32 | +import org.junit.jupiter.api.AfterAll; | 
|  | 33 | +import org.junit.jupiter.api.BeforeAll; | 
|  | 34 | +import org.junit.jupiter.api.Test; | 
|  | 35 | +import org.junit.jupiter.api.extension.RegisterExtension; | 
|  | 36 | + | 
|  | 37 | +class JexTest { | 
|  | 38 | + | 
|  | 39 | +  @RegisterExtension | 
|  | 40 | +  private static final InstrumentationExtension testing = AgentInstrumentationExtension.create(); | 
|  | 41 | + | 
|  | 42 | +  private static Server app; | 
|  | 43 | +  private static int port; | 
|  | 44 | +  private static WebClient client; | 
|  | 45 | + | 
|  | 46 | +  @BeforeAll | 
|  | 47 | +  static void setup() { | 
|  | 48 | +    app = TestJexJavaApplication.initJex(); | 
|  | 49 | +    port = app.port(); | 
|  | 50 | +    client = WebClient.of("http://localhost:" + port); | 
|  | 51 | +  } | 
|  | 52 | + | 
|  | 53 | +  @AfterAll | 
|  | 54 | +  static void cleanup() { | 
|  | 55 | +    app.shutdown(); | 
|  | 56 | +  } | 
|  | 57 | + | 
|  | 58 | +  @Test | 
|  | 59 | +  void testSpanNameAndHttpRouteSpanWithPathParamResponseSuccessful() { | 
|  | 60 | +    String id = "123"; | 
|  | 61 | +    AggregatedHttpResponse response = client.get("/test/param/" + id).aggregate().join(); | 
|  | 62 | +    String content = response.contentUtf8(); | 
|  | 63 | + | 
|  | 64 | +    assertThat(content).isEqualTo(id); | 
|  | 65 | +    assertThat(response.status().code()).isEqualTo(200); | 
|  | 66 | +    testing.waitAndAssertTraces( | 
|  | 67 | +        trace -> | 
|  | 68 | +            trace.hasSpansSatisfyingExactly( | 
|  | 69 | +                span -> | 
|  | 70 | +                    span.hasName("GET /test/param/{id}") | 
|  | 71 | +                        .hasKind(SpanKind.SERVER) | 
|  | 72 | +                        .hasNoParent() | 
|  | 73 | +                        .hasAttributesSatisfyingExactly( | 
|  | 74 | +                            equalTo(URL_SCHEME, "http"), | 
|  | 75 | +                            equalTo(URL_PATH, "/test/param/" + id), | 
|  | 76 | +                            equalTo(HTTP_REQUEST_METHOD, "GET"), | 
|  | 77 | +                            equalTo(HTTP_RESPONSE_STATUS_CODE, 200), | 
|  | 78 | +                            satisfies(USER_AGENT_ORIGINAL, val -> val.isInstanceOf(String.class)), | 
|  | 79 | +                            equalTo(HTTP_ROUTE, "/test/param/{id}"), | 
|  | 80 | +                            equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), | 
|  | 81 | +                            equalTo(SERVER_ADDRESS, "localhost"), | 
|  | 82 | +                            equalTo(SERVER_PORT, port), | 
|  | 83 | +                            equalTo(CLIENT_ADDRESS, "127.0.0.1"), | 
|  | 84 | +                            equalTo(NETWORK_PEER_ADDRESS, "127.0.0.1"), | 
|  | 85 | +                            satisfies(NETWORK_PEER_PORT, val -> val.isInstanceOf(Long.class))))); | 
|  | 86 | +  } | 
|  | 87 | + | 
|  | 88 | +  @Test | 
|  | 89 | +  void testSpanNameAndHttpRouteSpanResponseError() { | 
|  | 90 | +    client.get("/test/error").aggregate().join(); | 
|  | 91 | + | 
|  | 92 | +    testing.waitAndAssertTraces( | 
|  | 93 | +        trace -> | 
|  | 94 | +            trace.hasSpansSatisfyingExactly( | 
|  | 95 | +                span -> | 
|  | 96 | +                    span.hasName("GET /test/error") | 
|  | 97 | +                        .hasKind(SpanKind.SERVER) | 
|  | 98 | +                        .hasNoParent() | 
|  | 99 | +                        .hasAttributesSatisfyingExactly( | 
|  | 100 | +                            equalTo(URL_SCHEME, "http"), | 
|  | 101 | +                            equalTo(URL_PATH, "/test/error"), | 
|  | 102 | +                            equalTo(HTTP_REQUEST_METHOD, "GET"), | 
|  | 103 | +                            equalTo(HTTP_RESPONSE_STATUS_CODE, 500), | 
|  | 104 | +                            satisfies(USER_AGENT_ORIGINAL, val -> val.isInstanceOf(String.class)), | 
|  | 105 | +                            equalTo(HTTP_ROUTE, "/test/error"), | 
|  | 106 | +                            equalTo(NETWORK_PROTOCOL_VERSION, "1.1"), | 
|  | 107 | +                            equalTo(SERVER_ADDRESS, "localhost"), | 
|  | 108 | +                            equalTo(SERVER_PORT, port), | 
|  | 109 | +                            equalTo(ERROR_TYPE, "500"), | 
|  | 110 | +                            equalTo(CLIENT_ADDRESS, "127.0.0.1"), | 
|  | 111 | +                            equalTo(NETWORK_PEER_ADDRESS, "127.0.0.1"), | 
|  | 112 | +                            satisfies(NETWORK_PEER_PORT, val -> val.isInstanceOf(Long.class))))); | 
|  | 113 | +  } | 
|  | 114 | + | 
|  | 115 | +  @Test | 
|  | 116 | +  void testHttpRouteMetricWithPathParamResponseSuccessful() { | 
|  | 117 | +    String id = "123"; | 
|  | 118 | +    AggregatedHttpResponse response = client.get("/test/param/" + id).aggregate().join(); | 
|  | 119 | +    String content = response.contentUtf8(); | 
|  | 120 | +    String instrumentation = "io.opentelemetry.jetty-12.0"; | 
|  | 121 | + | 
|  | 122 | +    assertThat(content).isEqualTo(id); | 
|  | 123 | +    assertThat(response.status().code()).isEqualTo(200); | 
|  | 124 | +    testing.waitAndAssertMetrics( | 
|  | 125 | +        instrumentation, | 
|  | 126 | +        "http.server.request.duration", | 
|  | 127 | +        metrics -> | 
|  | 128 | +            metrics.anySatisfy( | 
|  | 129 | +                metric -> | 
|  | 130 | +                    assertThat(metric) | 
|  | 131 | +                        .hasHistogramSatisfying( | 
|  | 132 | +                            histogram -> | 
|  | 133 | +                                histogram.hasPointsSatisfying( | 
|  | 134 | +                                    point -> point.hasAttribute(HTTP_ROUTE, "/test/param/{id}"))))); | 
|  | 135 | +  } | 
|  | 136 | +} | 
0 commit comments