From 4d21d45f3db27832c7fca54dcf6a6381acf74334 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Tue, 4 Apr 2023 19:54:10 +0300 Subject: [PATCH] Verify that server span ends after child spans in java tests (#8208) Currently server span end time verification is only implemented for groovy tests. --- .../ktor/v1_0/KtorHttpServerTest.kt | 3 +++ .../ktor/v2_0/server/KtorHttpServerTest.kt | 4 ++++ .../testing/junit/http/AbstractHttpServerTest.java | 12 ++++++++++++ .../testing/junit/http/HttpServerTestOptions.java | 7 +++++++ .../java/org/assertj/core/api/AssertAccess.java | 14 ++++++++++++++ 5 files changed, 40 insertions(+) create mode 100644 testing-common/src/main/java/org/assertj/core/api/AssertAccess.java diff --git a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.kt b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.kt index 092f04ec8a..2d80e4ecb7 100644 --- a/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.kt +++ b/instrumentation/ktor/ktor-1.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v1_0/KtorHttpServerTest.kt @@ -134,5 +134,8 @@ class KtorHttpServerTest : AbstractHttpServerTest() { else -> expectedHttpRoute(it) } } + // ktor does not have a controller lifecycle so the server span ends immediately when the + // response is sent, which is before the controller span finishes. + options.setVerifyServerSpanEndTime(false) } } diff --git a/instrumentation/ktor/ktor-2.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorHttpServerTest.kt b/instrumentation/ktor/ktor-2.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorHttpServerTest.kt index 91b11caa85..177261fdea 100644 --- a/instrumentation/ktor/ktor-2.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorHttpServerTest.kt +++ b/instrumentation/ktor/ktor-2.0/library/src/test/kotlin/io/opentelemetry/instrumentation/ktor/v2_0/server/KtorHttpServerTest.kt @@ -134,5 +134,9 @@ class KtorHttpServerTest : AbstractHttpServerTest() { else -> expectedHttpRoute(it) } } + + // ktor does not have a controller lifecycle so the server span ends immediately when the + // response is sent, which is before the controller span finishes. + options.setVerifyServerSpanEndTime(false) } } diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java index dda5f6e699..92512f2098 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/AbstractHttpServerTest.java @@ -48,6 +48,7 @@ import java.util.concurrent.CountDownLatch; import java.util.function.Consumer; import java.util.function.Supplier; import javax.annotation.Nullable; +import org.assertj.core.api.AssertAccess; import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -466,6 +467,17 @@ public abstract class AbstractHttpServerTest extends AbstractHttpServerU } trace.hasSpansSatisfyingExactly(spanAssertions); + + if (options.verifyServerSpanEndTime) { + List spanData = AssertAccess.getActual(trace); + if (spanData.size() > 1) { + SpanData rootSpan = spanData.get(0); + for (int j = 1; j < spanData.size(); j++) { + assertThat(rootSpan.getEndEpochNanos()) + .isGreaterThanOrEqualTo(spanData.get(j).getEndEpochNanos()); + } + } + } }); } diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerTestOptions.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerTestOptions.java index 5982d9c749..34d1b0b9dc 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerTestOptions.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/http/HttpServerTestOptions.java @@ -51,6 +51,7 @@ public final class HttpServerTestOptions { boolean testPathParam = false; boolean testCaptureHttpHeaders = true; boolean testCaptureRequestParameters = false; + boolean verifyServerSpanEndTime = true; HttpServerTestOptions() {} @@ -174,6 +175,12 @@ public final class HttpServerTestOptions { return this; } + @CanIgnoreReturnValue + public HttpServerTestOptions setVerifyServerSpanEndTime(boolean verifyServerSpanEndTime) { + this.verifyServerSpanEndTime = verifyServerSpanEndTime; + return this; + } + @FunctionalInterface public interface SpanNameMapper { diff --git a/testing-common/src/main/java/org/assertj/core/api/AssertAccess.java b/testing-common/src/main/java/org/assertj/core/api/AssertAccess.java new file mode 100644 index 0000000000..f514eee0fa --- /dev/null +++ b/testing-common/src/main/java/org/assertj/core/api/AssertAccess.java @@ -0,0 +1,14 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.assertj.core.api; + +public final class AssertAccess { + private AssertAccess() {} + + public static ACTUAL getActual(AbstractAssert abstractAssert) { + return abstractAssert.actual; + } +}