From 3161309232cf4b548d6243e49fcd200b75830b44 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 16 Sep 2025 17:30:49 +0200 Subject: [PATCH 01/12] convert spring boot smoke test to java --- .../smoketest/JavaTelemetryRetriever.java | 8 +- .../opentelemetry/smoketest/TargetRunner.java | 5 +- .../smoketest/SpringBootSmokeTest.groovy | 116 ---------------- .../smoketest/AgentDebugLoggingTest.java | 2 +- .../smoketest/JavaSmokeTest.java | 47 +++++-- .../smoketest/LogsSmokeTest.java | 4 +- .../smoketest/QuarkusSmokeTest.java | 4 +- .../smoketest/SecurityManagerSmokeTest.java | 4 +- .../smoketest/SpringBootSmokeTest.java | 125 ++++++++++++++++++ .../testing/InstrumentationTestRunner.java | 21 +-- .../testing/junit/MetricsAssert.java | 55 ++++++++ 11 files changed, 238 insertions(+), 153 deletions(-) delete mode 100644 smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java create mode 100644 testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java index 3670c089c70f..549942c0f1ae 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java @@ -44,14 +44,14 @@ public List waitForTraces() { convert(requests, ExportTraceServiceRequest::getResourceSpansList)); } - public Collection waitForMetrics() { + public List waitForMetrics() { Collection requests = waitForTelemetry("get-metrics", ExportMetricsServiceRequest::newBuilder); return TelemetryConverter.getMetricsData( convert(requests, ExportMetricsServiceRequest::getResourceMetricsList)); } - public Collection waitForLogs() { + public List waitForLogs() { Collection requests = waitForTelemetry("get-logs", ExportLogsServiceRequest::newBuilder); return TelemetryConverter.getLogRecordData( @@ -104,6 +104,10 @@ private String waitForContent(String path) throws InterruptedException { TimeUnit.MILLISECONDS.sleep(500); } + if ("true".equals(System.getenv("debug"))) { + System.out.println(content); + } + return content; } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java index 57ff7c14bf97..aa6f04e7c99f 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java @@ -5,7 +5,10 @@ package io.opentelemetry.smoketest; +import java.util.function.Consumer; +import org.testcontainers.containers.output.OutputFrame; + @FunctionalInterface public interface TargetRunner { - void runInTarget() throws Exception; + void runInTarget(Consumer startTarget) throws Exception; } diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy deleted file mode 100644 index fcff6b54ae5d..000000000000 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SpringBootSmokeTest.groovy +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest - -import io.opentelemetry.api.trace.TraceId -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest -import spock.lang.IgnoreIf -import spock.lang.Unroll - -import java.time.Duration -import java.util.jar.Attributes -import java.util.jar.JarFile - -import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers -import static java.util.stream.Collectors.toSet - -@IgnoreIf({ useWindowsContainers() }) -class SpringBootSmokeTest extends SmokeTest { - - protected String getTargetImage(String jdk) { - "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20241021.11448062567" - } - - @Override - protected boolean getSetServiceName() { - return false - } - - @Override - protected Map getExtraEnv() { - return ["OTEL_METRICS_EXPORTER": "otlp", "OTEL_RESOURCE_ATTRIBUTES": "foo=bar"] - } - - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Started SpringbootApplication in.*") - } - - @Unroll - def "spring boot smoke test on JDK #jdk"(int jdk) { - setup: - def output = startTarget(jdk) - def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name.IMPLEMENTATION_VERSION).toString() - - when: - def response = client().get("/greeting").aggregate().join() - Collection traces = waitForTraces() - - then: "spans are exported" - response.contentUtf8() == "Hi!" - countSpansByName(traces, 'GET /greeting') == 1 - countSpansByName(traces, 'WebController.withSpan') == 1 - - then: "thread details are recorded" - getSpanStream(traces) - .allMatch { it.attributesList.stream().map { it.key }.collect(toSet()).containsAll(["thread.id", "thread.name"]) } - - then: "correct agent version is captured in the resource" - [currentAgentVersion] as Set == findResourceAttribute(traces, "telemetry.distro.version") - .map { it.stringValue } - .collect(toSet()) - - then: "OS is captured in the resource" - findResourceAttribute(traces, "os.type") - .map { it.stringValue } - .findAny() - .isPresent() - - then: "javaagent logs its version on startup" - isVersionLogged(output, currentAgentVersion) - - then: "correct traceIds are logged via MDC instrumentation" - def loggedTraceIds = getLoggedTraceIds(output) - def spanTraceIds = getSpanStream(traces) - .map({ TraceId.fromBytes(it.getTraceId().toByteArray()) }) - .collect(toSet()) - loggedTraceIds == spanTraceIds - - then: "JVM metrics are exported" - def metrics = new MetricsInspector(waitForMetrics()) - metrics.hasMetricsNamed("jvm.memory.used") - metrics.hasMetricsNamed("jvm.memory.committed") - metrics.hasMetricsNamed("jvm.memory.limit") - metrics.hasMetricsNamed("jvm.memory.used_after_last_gc") - - then: "resource attributes are read from the environment" - def foo = findResourceAttribute(traces, "foo") - .map { it.stringValue } - .findAny() - foo.isPresent() - foo.get() == "bar" - - then: "service name is autodetected" - def serviceName = findResourceAttribute(traces, "service.name") - .map { it.stringValue } - .findAny() - serviceName.isPresent() - serviceName.get() == "otel-spring-test-app" - - then: "service version is autodetected" - def serviceVersion = findResourceAttribute(traces, "service.version") - .map { it.stringValue } - .findAny() - serviceVersion.isPresent() - serviceVersion.get() == "2.10.0-alpha-SNAPSHOT" - - cleanup: - stopTarget() - - where: - jdk << [8, 11, 17, 21, 23] - } -} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java index 3e881f6fb41c..45728b98af94 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java @@ -28,6 +28,6 @@ protected TargetWaitStrategy getWaitStrategy() { @DisplayName("verifies that debug logging is working by checking for a debug log on startup") @Test void verifyLogging() throws Exception { - withTarget(8, () -> {}); + runTarget(8, output -> {}); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 9c4f23053447..1a85f0fcdbbb 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -7,20 +7,29 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toSet; +import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.assertj.MetricAssert; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.smoketest.windows.WindowsTestContainerManager; import io.opentelemetry.testing.internal.armeria.client.WebClient; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Consumer; +import java.util.regex.Pattern; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.ToStringConsumer; public abstract class JavaSmokeTest { + private static final Pattern TRACE_ID_PATTERN = + Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); + protected static final TestContainerManager containerManager = createContainerManager(); private JavaTelemetryRetriever telemetryRetriever; @@ -65,16 +74,16 @@ void setUp() { telemetryRetriever = new JavaTelemetryRetriever(containerManager.getBackendMappedPort()); } - public void withTarget(int jdk, TargetRunner runner) throws Exception { - startTarget(jdk); + public void runTarget(int jdk, TargetRunner runner) throws Exception { + Consumer startTarget = startTarget(jdk); try { - runner.runInTarget(); + runner.runInTarget(startTarget); } finally { stopTarget(); } } - public Consumer startTarget(int jdk) { + private Consumer startTarget(int jdk) { return startTarget(String.valueOf(jdk), null, false); } @@ -110,7 +119,7 @@ public void cleanup() { telemetryRetriever.clearTelemetry(); } - public void stopTarget() { + private void stopTarget() { containerManager.stopTarget(); cleanup(); } @@ -119,14 +128,36 @@ protected List waitForTraces() { return telemetryRetriever.waitForTraces(); } - protected Collection waitForMetrics() { - return telemetryRetriever.waitForMetrics(); + @SafeVarargs + @SuppressWarnings("varargs") + protected final void waitAndAssertMetrics( + String instrumentationName, Consumer... assertions) { + MetricsAssert.waitAndAssertMetrics( + () -> telemetryRetriever.waitForMetrics(), instrumentationName, assertions); } protected Collection waitForLogs() { return telemetryRetriever.waitForLogs(); } + protected static boolean isVersionLogged(Consumer output, String version) { + return logLines(output) + .anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version)); + } + + private static Stream logLines(Consumer output) { + return ((ToStringConsumer) output).toUtf8String().lines(); + } + + protected static Set getLoggedTraceIds(Consumer output) { + return logLines(output).flatMap(l -> findTraceId(l)).collect(toSet()); + } + + private static Stream findTraceId(String log) { + var m = TRACE_ID_PATTERN.matcher(log); + return m.matches() ? Stream.of(m.group("traceId")) : Stream.empty(); + } + private static TestContainerManager createContainerManager() { return TestContainerManager.useWindowsContainers() ? new WindowsTestContainerManager() diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java index c49fb4311bf8..9cd060c080c1 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java @@ -32,9 +32,9 @@ protected TargetWaitStrategy getWaitStrategy() { @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void shouldExportLogs(int jdk) throws Exception { - withTarget( + runTarget( jdk, - () -> { + output -> { client().get("/greeting").aggregate().join(); Collection logs = waitForLogs(); diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java index c2ab2a37f693..7564b327df35 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java @@ -38,9 +38,9 @@ protected boolean getSetServiceName() { @ParameterizedTest @ValueSource(ints = {17, 21, 23}) // Quarkus 3.7+ requires Java 17+ void quarkusSmokeTest(int jdk) throws Exception { - withTarget( + runTarget( jdk, - () -> { + output -> { String currentAgentVersion; try (JarFile agentJar = new JarFile(agentPath)) { currentAgentVersion = diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index 216255628f65..307e01fff404 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -31,9 +31,9 @@ protected Map getExtraEnv() { @ParameterizedTest @ValueSource(ints = {8, 11, 17, 21, 23}) void securityManagerSmokeTest(int jdk) throws Exception { - withTarget( + runTarget( jdk, - () -> + output -> assertThat(waitForTraces()) .hasTracesSatisfyingExactly( trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("test")))); diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java new file mode 100644 index 000000000000..0f5dfaf45643 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -0,0 +1,125 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +import io.opentelemetry.api.common.AttributeKey; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.ServiceAttributes; +import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; +import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; +import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.stream.Collectors; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class SpringBootSmokeTest extends JavaSmokeTest { + @Override + protected String getTargetImage(String jdk) { + return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" + + jdk + + "-20241021.11448062567"; + } + + @Override + protected boolean getSetServiceName() { + return false; + } + + @Override + protected Map getExtraEnv() { + return Map.of("OTEL_METRICS_EXPORTER", "otlp", "OTEL_RESOURCE_ATTRIBUTES", "foo=bar"); + } + + @Override + protected TargetWaitStrategy getWaitStrategy() { + return new TargetWaitStrategy.Log( + Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); + } + + @ParameterizedTest + @ValueSource(ints = {8, 11, 17, 21, 23}) + void springBootSmokeTest(int jdk) throws Exception { + runTarget( + jdk, + output -> { + String currentAgentVersion; + try (JarFile agentJar = new JarFile(agentPath)) { + currentAgentVersion = + agentJar + .getManifest() + .getMainAttributes() + .getValue(Attributes.Name.IMPLEMENTATION_VERSION); + } + + var response = client().get("/greeting").aggregate().join(); + assertThat(response.contentUtf8()).isEqualTo("Hi!"); + + List traces = waitForTraces(); + assertThat(traces) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /greeting") + .hasAttribute( + satisfies( + ThreadIncubatingAttributes.THREAD_ID, a -> a.isNotNull())) + .hasAttribute( + satisfies( + ThreadIncubatingAttributes.THREAD_NAME, + a -> a.isNotBlank())) + .hasResourceSatisfying( + resource -> + resource + .hasAttribute( + TelemetryIncubatingAttributes + .TELEMETRY_DISTRO_VERSION, + currentAgentVersion) + .hasAttribute( + satisfies( + OsIncubatingAttributes.OS_TYPE, + a -> a.isNotNull())) + .hasAttribute(AttributeKey.stringKey("foo"), "bar") + .hasAttribute( + ServiceAttributes.SERVICE_NAME, + "otel-spring-test-app") + .hasAttribute( + ServiceAttributes.SERVICE_VERSION, + "2.10.0-alpha-SNAPSHOT")), + span -> span.hasName("WebController.withSpan"))); + + // Check agent version is logged on startup + assertThat(isVersionLogged(output, currentAgentVersion)).isTrue(); + + // Check trace IDs are logged via MDC instrumentation + Set loggedTraceIds = getLoggedTraceIds(output); + Set spanTraceIds = + traces.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); + assertThat(loggedTraceIds).isEqualTo(spanTraceIds); + + // Check JVM metrics are exported + waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + metric -> metric.hasName("jvm.memory.used"), + metric -> metric.hasName("jvm.memory.committed"), + metric -> metric.hasName("jvm.memory.limit"), + metric -> metric.hasName("jvm.memory.used_after_last_gc")); + }); + } +} diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java index b63bb7bd3550..d9dbafbc38cb 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java @@ -13,6 +13,7 @@ import io.opentelemetry.api.common.AttributeType; import io.opentelemetry.api.internal.InternalAttributeKeyImpl; import io.opentelemetry.api.trace.SpanKind; +import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; import io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil; import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable; import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier; @@ -27,7 +28,6 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -35,7 +35,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; -import java.util.stream.Collectors; import javax.annotation.Nullable; import org.assertj.core.api.ListAssert; import org.awaitility.core.ConditionFactory; @@ -186,17 +185,7 @@ public final void waitAndAssertMetrics( public final void waitAndAssertMetrics( String instrumentationName, Consumer... assertions) { awaitUntilAsserted( - () -> { - Collection metrics = instrumentationMetrics(instrumentationName); - assertThat(metrics).isNotEmpty(); - for (int i = 0; i < assertions.length; i++) { - int index = i; - assertThat(metrics) - .describedAs( - "Metrics for instrumentation %s and assertion %d", instrumentationName, index) - .anySatisfy(metric -> assertions[index].accept(assertThat(metric))); - } - }); + () -> MetricsAssert.assertMetrics(getExportedMetrics(), instrumentationName, assertions)); if (Boolean.getBoolean("collectMetadata")) { collectEmittedMetrics(getExportedMetrics()); @@ -246,12 +235,6 @@ public final List waitForLogRecords(int numberOfLogRecords) { return getExportedLogRecords(); } - private List instrumentationMetrics(String instrumentationName) { - return getExportedMetrics().stream() - .filter(m -> m.getInstrumentationScopeInfo().getName().equals(instrumentationName)) - .collect(Collectors.toList()); - } - /** * Runs the provided {@code callback} inside the scope of an INTERNAL span with name {@code * spanName}. diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java new file mode 100644 index 000000000000..081f4287fd92 --- /dev/null +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.instrumentation.testing.junit; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.assertj.MetricAssert; +import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; +import java.util.Collection; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class MetricsAssert { + + @SafeVarargs + public static void waitAndAssertMetrics( + Supplier> metricData, + String instrumentationName, + Consumer... assertions) { + await().untilAsserted(() -> assertMetrics(metricData.get(), instrumentationName, assertions)); + } + + @SafeVarargs + public static void assertMetrics( + List metricData, + String instrumentationName, + Consumer... assertions) { + Collection metrics = instrumentationMetrics(instrumentationName, metricData); + assertThat(metrics).isNotEmpty(); + for (int i = 0; i < assertions.length; i++) { + int index = i; + assertThat(metrics) + .describedAs( + "Metrics for instrumentation %s and assertion %d", instrumentationName, index) + .anySatisfy( + metric -> assertions[index].accept(OpenTelemetryAssertions.assertThat(metric))); + } + } + + private static List instrumentationMetrics( + String instrumentationName, List metrics) { + return metrics.stream() + .filter(m -> m.getInstrumentationScopeInfo().getName().equals(instrumentationName)) + .collect(Collectors.toList()); + } + + private MetricsAssert() {} +} From 37fe8189e8706dc4b1f0353bd7ecfb74babacbbd Mon Sep 17 00:00:00 2001 From: otelbot <197425009+otelbot@users.noreply.github.com> Date: Tue, 16 Sep 2025 16:38:39 +0000 Subject: [PATCH 02/12] ./gradlew spotlessApply --- .../smoketest/SpringBootSmokeTest.java | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index 0f5dfaf45643..9b88be3a1d75 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -5,16 +5,16 @@ package io.opentelemetry.smoketest; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; + import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.semconv.ServiceAttributes; import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; -import org.junit.jupiter.api.condition.DisabledIf; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - import java.time.Duration; import java.util.List; import java.util.Map; @@ -22,10 +22,9 @@ import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.stream.Collectors; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SpringBootSmokeTest extends JavaSmokeTest { From 1ee691e199f10d5aa086049df01f9168be2e2ef9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 16 Sep 2025 18:47:47 +0200 Subject: [PATCH 03/12] convert declarative config test --- .../DeclarativeConfigurationSmokeTest.groovy | 78 ---------------- .../DeclarativeConfigurationSmokeTest.java | 93 +++++++++++++++++++ 2 files changed, 93 insertions(+), 78 deletions(-) delete mode 100644 smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy deleted file mode 100644 index 0e111ceaa442..000000000000 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.groovy +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest - - -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest -import spock.lang.IgnoreIf -import spock.lang.Unroll - -import java.time.Duration - -import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers - -@IgnoreIf({ useWindowsContainers() }) -class DeclarativeConfigurationSmokeTest extends SmokeTest { - - protected String getTargetImage(String jdk) { - "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20241021.11448062567" - } - - @Override - protected List getExtraResources() { - [ - ResourceMapping.of("declarative-config.yaml", "/declarative-config.yaml"), - ] - } - - @Override - protected Map getExtraEnv() { - return ["OTEL_EXPERIMENTAL_CONFIG_FILE": "declarative-config.yaml"] - } - - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Started SpringbootApplication in.*") - } - - @Unroll - def "spring boot smoke test on JDK #jdk"(int jdk) { - setup: - startTarget(jdk) - - when: - client().get("/greeting").aggregate().join() - Collection traces = waitForTraces() - - then: "There is one trace" - traces.size() == 1 - - then: "There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 " + - "is not used, because instrumentation_mode=none)" - getSpanStream(traces).count() == 1 - - then: "explicitly set attribute is present" - hasResourceAttribute(traces, "service.name", "declarative-config-smoke-test") - - then: "explicitly set container detector is used" - findResourceAttribute(traces, "container.id").findAny().isPresent() - - then: "explicitly set container process detector is used" - findResourceAttribute(traces, "process.executable.path").findAny().isPresent() - - then: "explicitly set container host detector is used" - findResourceAttribute(traces, "host.name").findAny().isPresent() - - then: "distro detector is added by customizer" - hasResourceAttribute(traces, "telemetry.distro.name", "opentelemetry-javaagent") - - cleanup: - stopTarget() - - where: - jdk << [8, 11, 17] - } -} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java new file mode 100644 index 000000000000..a91616e6af1c --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -0,0 +1,93 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +import io.opentelemetry.sdk.testing.assertj.TracesAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.semconv.ServiceAttributes; +import io.opentelemetry.semconv.incubating.ContainerIncubatingAttributes; +import io.opentelemetry.semconv.incubating.HostIncubatingAttributes; +import io.opentelemetry.semconv.incubating.ProcessIncubatingAttributes; +import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.time.Duration; +import java.util.List; +import java.util.Map; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class DeclarativeConfigurationSmokeTest extends JavaSmokeTest { + @Override + protected String getTargetImage(String jdk) { + return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" + + jdk + + "-20241021.11448062567"; + } + + @Override + protected List getExtraResources() { + return List.of(ResourceMapping.of("declarative-config.yaml", "/declarative-config.yaml")); + } + + @Override + protected Map getExtraEnv() { + return Map.of("OTEL_EXPERIMENTAL_CONFIG_FILE", "declarative-config.yaml"); + } + + @Override + protected TargetWaitStrategy getWaitStrategy() { + return new TargetWaitStrategy.Log( + Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); + } + + @ParameterizedTest + @ValueSource(ints = {8, 11, 17}) + void springBootSmokeTest(int jdk) throws Exception { + runTarget( + jdk, + output -> { + client().get("/greeting").aggregate().join(); + List traces = waitForTraces(); + assertThat(traces).hasSize(1); + + // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is + // not used, + // because instrumentation_mode=none) + TracesAssert.assertThat(traces) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasResourceSatisfying( + resource -> + resource + .hasAttribute( + ServiceAttributes.SERVICE_NAME, + "declarative-config-smoke-test") + .hasAttribute( + satisfies( + ContainerIncubatingAttributes.CONTAINER_ID, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + ProcessIncubatingAttributes + .PROCESS_EXECUTABLE_PATH, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + HostIncubatingAttributes.HOST_NAME, + v -> v.isNotBlank())) + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME, + "opentelemetry-javaagent")))); + }); + } +} From c8b6c3cf4a25e561784c816b1b2803d63fe033d4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 16 Sep 2025 18:59:09 +0200 Subject: [PATCH 04/12] convert disabled config test --- .../smoketest/SdkDisabledSmokeTest.groovy | 59 ------------------- .../DeclarativeConfigurationSmokeTest.java | 13 ++-- .../smoketest/JavaSmokeTest.java | 17 ++++-- .../smoketest/SdkDisabledSmokeTest.java | 50 ++++++++++++++++ .../smoketest/SpringBootSmokeTest.java | 2 +- .../testing/junit/MetricsAssert.java | 6 +- 6 files changed, 71 insertions(+), 76 deletions(-) delete mode 100644 smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SdkDisabledSmokeTest.groovy create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SdkDisabledSmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SdkDisabledSmokeTest.groovy deleted file mode 100644 index 0177a6355c96..000000000000 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SdkDisabledSmokeTest.groovy +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest - -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest -import spock.lang.IgnoreIf -import spock.lang.Unroll - -import java.util.jar.Attributes -import java.util.jar.JarFile - -import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers - -@IgnoreIf({ useWindowsContainers() }) -class SdkDisabledSmokeTest extends SmokeTest { - - protected String getTargetImage(String jdk) { - "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20211213.1570880324" - } - - @Override - protected Map getExtraEnv() { - return [ - "OTEL_SDK_DISABLED": "true" - ] - } - - @Unroll - def "noop sdk smoke test on JDK #jdk"(int jdk) { - setup: - def output = startTarget(jdk) - def currentAgentVersion = new JarFile(agentPath).getManifest().getMainAttributes().get(Attributes.Name.IMPLEMENTATION_VERSION).toString() - - when: - def response = client().get("/greeting").aggregate().join() - Collection traces = waitForTraces() - - then: "no spans are exported" - response.contentUtf8() == "Hi!" - traces.isEmpty() - - then: "javaagent logs its version on startup" - isVersionLogged(output, currentAgentVersion) - - - then: "no metrics are exported" - def metrics = new MetricsInspector(waitForMetrics()) - metrics.requests.isEmpty() - - cleanup: - stopTarget() - - where: - jdk << [8, 11, 17] - } -} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java index a91616e6af1c..2c444acab138 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -5,6 +5,9 @@ package io.opentelemetry.smoketest; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; + import io.opentelemetry.sdk.testing.assertj.TracesAssert; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.semconv.ServiceAttributes; @@ -12,16 +15,12 @@ import io.opentelemetry.semconv.incubating.HostIncubatingAttributes; import io.opentelemetry.semconv.incubating.ProcessIncubatingAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; -import org.junit.jupiter.api.condition.DisabledIf; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; - import java.time.Duration; import java.util.List; import java.util.Map; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class DeclarativeConfigurationSmokeTest extends JavaSmokeTest { diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 1a85f0fcdbbb..46835a72a6b4 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -8,9 +8,11 @@ import static java.util.Collections.emptyList; import static java.util.Collections.emptyMap; import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.assertj.MetricAssert; import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.smoketest.windows.WindowsTestContainerManager; @@ -132,17 +134,22 @@ protected List waitForTraces() { @SuppressWarnings("varargs") protected final void waitAndAssertMetrics( String instrumentationName, Consumer... assertions) { - MetricsAssert.waitAndAssertMetrics( - () -> telemetryRetriever.waitForMetrics(), instrumentationName, assertions); + MetricsAssert.waitAndAssertMetrics(() -> waitForMetrics(), instrumentationName, assertions); + } + + protected List waitForMetrics() { + return telemetryRetriever.waitForMetrics(); } protected Collection waitForLogs() { return telemetryRetriever.waitForLogs(); } - protected static boolean isVersionLogged(Consumer output, String version) { - return logLines(output) - .anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version)); + protected static void assertVersionLogged(Consumer output, String version) { + assertThat( + logLines(output) + .anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version))) + .isTrue(); } private static Stream logLines(Consumer output) { diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java new file mode 100644 index 000000000000..cc774c723d93 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; + +import java.util.Map; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class SdkDisabledSmokeTest extends JavaSmokeTest { + @Override + protected String getTargetImage(String jdk) { + return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" + + jdk + + "-20211213.1570880324"; + } + + @Override + protected Map getExtraEnv() { + return Map.of("OTEL_SDK_DISABLED", "true"); + } + + @ParameterizedTest + @ValueSource(ints = {8, 11, 17}) + void noopSdkSmokeTest(int jdk) throws Exception { + runTarget( + jdk, + output -> { + String currentAgentVersion = + new JarFile(agentPath) + .getManifest() + .getMainAttributes() + .get(Attributes.Name.IMPLEMENTATION_VERSION) + .toString(); + + assertThat(client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); + assertThat(waitForTraces()).isEmpty(); + assertVersionLogged(output, currentAgentVersion); + assertThat(waitForTraces()).isEmpty(); + }); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index 9b88be3a1d75..fefcb0ce8abb 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -104,7 +104,7 @@ void springBootSmokeTest(int jdk) throws Exception { span -> span.hasName("WebController.withSpan"))); // Check agent version is logged on startup - assertThat(isVersionLogged(output, currentAgentVersion)).isTrue(); + assertVersionLogged(output, currentAgentVersion); // Check trace IDs are logged via MDC instrumentation Set loggedTraceIds = getLoggedTraceIds(output); diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java index 081f4287fd92..79ecef1396bf 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java @@ -5,12 +5,11 @@ package io.opentelemetry.instrumentation.testing.junit; -import static org.assertj.core.api.Assertions.assertThat; +import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static org.awaitility.Awaitility.await; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.testing.assertj.MetricAssert; -import io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions; import java.util.Collection; import java.util.List; import java.util.function.Consumer; @@ -39,8 +38,7 @@ public static void assertMetrics( assertThat(metrics) .describedAs( "Metrics for instrumentation %s and assertion %d", instrumentationName, index) - .anySatisfy( - metric -> assertions[index].accept(OpenTelemetryAssertions.assertThat(metric))); + .anySatisfy(metric -> assertions[index].accept(assertThat(metric))); } } From 2afc6a1408d87bbaeace6c16b8e0e0de3467a4f5 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 16 Sep 2025 20:07:41 +0200 Subject: [PATCH 05/12] convert propagation test --- .../smoketest/PropagationTest.groovy | 128 ------------------ .../propagation/B3MultiPropagationTest.java | 17 +++ .../propagation/B3PropagationTest.java | 17 +++ .../propagation/DefaultPropagationTest.java | 11 ++ .../propagation/OtTracePropagationTest.java | 60 ++++++++ .../propagation/PropagationTest.java | 48 +++++++ .../propagation/W3CPropagationTest.java | 17 +++ .../propagation/XRayPropagationTest.java | 17 +++ 8 files changed, 187 insertions(+), 128 deletions(-) delete mode 100644 smoke-tests/src/test/groovy/io/opentelemetry/smoketest/PropagationTest.groovy create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java create mode 100644 smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/PropagationTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/PropagationTest.groovy deleted file mode 100644 index 690fdc556c39..000000000000 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/PropagationTest.groovy +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest - -import io.opentelemetry.api.trace.TraceId -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest -import spock.lang.IgnoreIf - -import java.time.Duration - -import static io.opentelemetry.smoketest.TestContainerManager.useWindowsContainers -import static java.util.stream.Collectors.toSet - -abstract class PropagationTest extends SmokeTest { - - @Override - protected String getTargetImage(String jdk) { - "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20211213.1570880324" - } - - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Started SpringbootApplication in.*") - } - - def "Should propagate test"() { - setup: - startTarget(11) - when: - def response = client().get("/front").aggregate().join() - Collection traces = waitForTraces() - def traceIds = getSpanStream(traces) - .map({ TraceId.fromBytes(it.getTraceId().toByteArray()) }) - .collect(toSet()) - - then: - traceIds.size() == 1 - - def traceId = traceIds.first() - - response.contentUtf8() == "${traceId};${traceId}" - - cleanup: - stopTarget() - - } - -} - -@IgnoreIf({ useWindowsContainers() }) -class DefaultPropagationTest extends PropagationTest { -} - -@IgnoreIf({ useWindowsContainers() }) -class W3CPropagationTest extends PropagationTest { - @Override - protected Map getExtraEnv() { - return ["otel.propagators": "tracecontext"] - } -} - -@IgnoreIf({ useWindowsContainers() }) -class B3PropagationTest extends PropagationTest { - @Override - protected Map getExtraEnv() { - return ["otel.propagators": "b3"] - } -} - -@IgnoreIf({ useWindowsContainers() }) -class B3MultiPropagationTest extends PropagationTest { - @Override - protected Map getExtraEnv() { - return ["otel.propagators": "b3multi"] - } -} - -@IgnoreIf({ useWindowsContainers() }) -class OtTracePropagationTest extends SmokeTest { - @Override - protected String getTargetImage(String jdk) { - "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk$jdk-20211213.1570880324" - } - - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Started SpringbootApplication in.*") - } - - // OtTracer only propagates lower half of trace ID so we have to mangle the trace IDs similar to - // the Lightstep backend. - def "Should propagate test"() { - setup: - startTarget(11) - when: - def response = client().get("/front").aggregate().join() - Collection traces = waitForTraces() - def traceIds = getSpanStream(traces) - .map({ TraceId.fromBytes(it.getTraceId().toByteArray()).substring(16) }) - .collect(toSet()) - - then: - traceIds.size() == 1 - - def traceId = traceIds.first() - - response.contentUtf8().matches(/[0-9a-f]{16}${traceId};[0]{16}${traceId}/) - - cleanup: - stopTarget() - } - - @Override - protected Map getExtraEnv() { - return ["otel.propagators": "ottrace"] - } -} - -@IgnoreIf({ useWindowsContainers() }) -class XRayPropagationTest extends PropagationTest { - @Override - protected Map getExtraEnv() { - return ["otel.propagators": "xray"] - } -} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java new file mode 100644 index 000000000000..db814482335c --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import java.util.Map; +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class B3MultiPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return Map.of("otel.propagators", "b3multi"); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java new file mode 100644 index 000000000000..73fc15912935 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import java.util.Map; +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class B3PropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return Map.of("otel.propagators", "b3"); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java new file mode 100644 index 000000000000..a765f0a43006 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java @@ -0,0 +1,11 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class DefaultPropagationTest extends PropagationTest {} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java new file mode 100644 index 000000000000..9ec469421f14 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java @@ -0,0 +1,60 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.smoketest.JavaSmokeTest; +import io.opentelemetry.smoketest.TargetWaitStrategy; +import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class OtTracePropagationTest extends JavaSmokeTest { + @Override + protected String getTargetImage(String jdk) { + return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" + + jdk + + "-20211213.1570880324"; + } + + @Override + protected TargetWaitStrategy getWaitStrategy() { + return new TargetWaitStrategy.Log( + Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); + } + + @Test + public void shouldPropagate() throws Exception { + runTarget( + 11, + output -> { + AggregatedHttpResponse response = client().get("/front").aggregate().join(); + List spanData = waitForTraces(); + + Set ids = + spanData.stream().map(s -> s.getTraceId().substring(16)).collect(Collectors.toSet()); + assertThat(ids).hasSize(1); + + var traceId = ids.iterator().next(); + + assertThat(response.contentUtf8()) + .matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); + }); + } + + @Override + protected Map getExtraEnv() { + return Map.of("otel.propagators", "ottrace"); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java new file mode 100644 index 000000000000..52f6357a27f6 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java @@ -0,0 +1,48 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.opentelemetry.sdk.testing.assertj.TracesAssert; +import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.smoketest.JavaSmokeTest; +import io.opentelemetry.smoketest.TargetWaitStrategy; +import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Test; + +public abstract class PropagationTest extends JavaSmokeTest { + + @Override + protected String getTargetImage(String jdk) { + return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" + + jdk + + "-20211213.1570880324"; + } + + @Override + protected TargetWaitStrategy getWaitStrategy() { + return new TargetWaitStrategy.Log( + Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); + } + + @Test + public void shouldPropagate() throws Exception { + runTarget( + 11, + output -> { + AggregatedHttpResponse response = client().get("/front").aggregate().join(); + List traces = waitForTraces(); + + TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(trace -> {}); + + var traceId = traces.get(0).getTraceId(); + assertThat(response.contentUtf8()).isEqualTo(traceId + ";" + traceId); + }); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java new file mode 100644 index 000000000000..5bb4b70da593 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import java.util.Map; +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class W3CPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return Map.of("otel.propagators", "tracecontext"); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java new file mode 100644 index 000000000000..71d2968457d5 --- /dev/null +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java @@ -0,0 +1,17 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest.propagation; + +import java.util.Map; +import org.junit.jupiter.api.condition.DisabledIf; + +@DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") +class XRayPropagationTest extends PropagationTest { + @Override + protected Map getExtraEnv() { + return Map.of("otel.propagators", "xray"); + } +} From 209e51b96140cb99cf6affec9d8ad13fd53b9f11 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Thu, 18 Sep 2025 12:11:32 +0200 Subject: [PATCH 06/12] smoke test extension --- .../smoketest/AbstractSmokeTest.java | 9 +++ .../SmokeTestInstrumentationExtension.java | 32 +++++++++ .../smoketest/SmokeTestRunner.java | 65 +++++++++++++++++++ .../smoketest/JavaSmokeTest.java | 12 ++-- .../smoketest/SecurityManagerSmokeTest.java | 20 +++--- .../testing/util/TelemetryDataUtil.java | 2 +- 6 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java create mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java create mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java new file mode 100644 index 000000000000..5cd16b9ee793 --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java @@ -0,0 +1,9 @@ +package io.opentelemetry.smoketest; + +import java.util.function.Consumer; +import org.junit.jupiter.api.TestInstance; + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public abstract class AbstractSmokeTest { + public abstract void configureTelemetryRetriever(Consumer action); +} diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java new file mode 100644 index 000000000000..cd868dc7ead9 --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java @@ -0,0 +1,32 @@ +package io.opentelemetry.smoketest; + +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; +import org.junit.jupiter.api.extension.ExtensionContext; + +public class SmokeTestInstrumentationExtension extends InstrumentationExtension { + private SmokeTestInstrumentationExtension() { + super(SmokeTestRunner.instance()); + } + + public static SmokeTestInstrumentationExtension create() { + return new SmokeTestInstrumentationExtension(); + } + + @Override + public void beforeEach(ExtensionContext extensionContext) { + Object testInstance = extensionContext.getRequiredTestInstance(); + + if (!(testInstance instanceof AbstractSmokeTest)) { + throw new AssertionError( + "SmokeTestInstrumentationExtension can only be applied to a subclass of " + + "AbstractSmokeTest"); + } + + SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); + ((AbstractSmokeTest) testInstance).configureTelemetryRetriever( + smokeTestRunner::setTelemetryRetriever); + + super.beforeEach(extensionContext); + } +} + diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java new file mode 100644 index 000000000000..5f81fabd7bd0 --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java @@ -0,0 +1,65 @@ +package io.opentelemetry.smoketest; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.instrumentation.testing.InstrumentationTestRunner; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.List; + +public class SmokeTestRunner extends InstrumentationTestRunner { + + private static final SmokeTestRunner INSTANCE = new SmokeTestRunner(); + + private JavaTelemetryRetriever telemetryRetriever; + + public static SmokeTestRunner instance() { + return INSTANCE; + } + + private SmokeTestRunner() { + super(OpenTelemetry.noop()); + } + + void setTelemetryRetriever(JavaTelemetryRetriever telemetryRetriever) { + this.telemetryRetriever = telemetryRetriever; + } + + @Override + public void beforeTestClass() { + } + + @Override + public void afterTestClass() { + } + + @Override + public void clearAllExportedData() { + telemetryRetriever.clearTelemetry(); + } + + @Override + public OpenTelemetry getOpenTelemetry() { + throw new UnsupportedOperationException(); + } + + @Override + public List getExportedSpans() { + return telemetryRetriever.waitForTraces(); + } + + @Override + public List getExportedMetrics() { + return telemetryRetriever.waitForMetrics(); + } + + @Override + public List getExportedLogRecords() { + return telemetryRetriever.waitForLogs(); + } + + @Override + public boolean forceFlushCalled() { + throw new UnsupportedOperationException(); + } +} diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 46835a72a6b4..578d3c2b824e 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -24,14 +24,13 @@ import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.BeforeAll; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.ToStringConsumer; -public abstract class JavaSmokeTest { +public abstract class JavaSmokeTest extends AbstractSmokeTest { private static final Pattern TRACE_ID_PATTERN = Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); - protected static final TestContainerManager containerManager = createContainerManager(); private JavaTelemetryRetriever telemetryRetriever; @@ -70,7 +69,7 @@ protected List getExtraPorts() { return emptyList(); } - @BeforeEach + @BeforeAll void setUp() { containerManager.startEnvironmentOnce(); telemetryRetriever = new JavaTelemetryRetriever(containerManager.getBackendMappedPort()); @@ -170,4 +169,9 @@ private static TestContainerManager createContainerManager() { ? new WindowsTestContainerManager() : new LinuxTestContainerManager(); } + + @Override + public void configureTelemetryRetriever(Consumer action) { + action.accept(telemetryRetriever); + } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index 307e01fff404..6622c2367011 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -5,16 +5,20 @@ package io.opentelemetry.smoketest; -import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; - +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import java.util.Collections; import java.util.Map; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SecurityManagerSmokeTest extends JavaSmokeTest { + @RegisterExtension static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); + @RegisterExtension static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + @Override protected String getTargetImage(String jdk) { return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-security-manager:jdk" @@ -30,12 +34,10 @@ protected Map getExtraEnv() { @ParameterizedTest @ValueSource(ints = {8, 11, 17, 21, 23}) - void securityManagerSmokeTest(int jdk) throws Exception { - runTarget( - jdk, - output -> - assertThat(waitForTraces()) - .hasTracesSatisfyingExactly( - trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("test")))); + void securityManagerSmokeTest(int jdk) { + startTarget(jdk); + autoCleanup.deferCleanup(this::stopTarget); + + testing.waitAndAssertTraces(trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("test"))); } } diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/util/TelemetryDataUtil.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/util/TelemetryDataUtil.java index 830b3fcfdcee..9780924c7e6a 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/util/TelemetryDataUtil.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/util/TelemetryDataUtil.java @@ -93,7 +93,7 @@ public static void assertScopeVersion(List> traces) { for (List trace : traces) { for (SpanData span : trace) { InstrumentationScopeInfo scopeInfo = span.getInstrumentationScopeInfo(); - if (!scopeInfo.getName().equals("test")) { + if (!scopeInfo.getName().startsWith("test")) { assertThat(scopeInfo.getVersion()) .as( "Instrumentation version of module %s was empty; make sure that the " From 3760f5ad6075a58a380e356c5d1bc942689d361c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 18 Sep 2025 13:00:33 +0200 Subject: [PATCH 07/12] rename --- ...t.java => AbstractRemoteTelemetryTest.java} | 4 ++-- ...ever.java => RemoteTelemetryRetriever.java} | 4 ++-- .../SmokeTestInstrumentationExtension.java | 4 ++-- .../smoketest/SmokeTestRunner.java | 4 ++-- .../opentelemetry/smoketest/JavaSmokeTest.java | 18 ++++++++++++------ .../smoketest/SecurityManagerSmokeTest.java | 9 ++++----- 6 files changed, 24 insertions(+), 19 deletions(-) rename smoke-tests/src/main/java/io/opentelemetry/smoketest/{AbstractSmokeTest.java => AbstractRemoteTelemetryTest.java} (53%) rename smoke-tests/src/main/java/io/opentelemetry/smoketest/{JavaTelemetryRetriever.java => RemoteTelemetryRetriever.java} (97%) diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java similarity index 53% rename from smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java rename to smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java index 5cd16b9ee793..dd5925f6a518 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractSmokeTest.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java @@ -4,6 +4,6 @@ import org.junit.jupiter.api.TestInstance; @TestInstance(TestInstance.Lifecycle.PER_CLASS) -public abstract class AbstractSmokeTest { - public abstract void configureTelemetryRetriever(Consumer action); +public abstract class AbstractRemoteTelemetryTest { + public abstract void configureTelemetryRetriever(Consumer action); } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java similarity index 97% rename from smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java rename to smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java index 549942c0f1ae..cef1d82eb463 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/JavaTelemetryRetriever.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java @@ -25,11 +25,11 @@ import java.util.function.Supplier; import java.util.stream.Collectors; -public class JavaTelemetryRetriever { +public class RemoteTelemetryRetriever { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private final WebClient client; - public JavaTelemetryRetriever(int backendPort) { + public RemoteTelemetryRetriever(int backendPort) { client = WebClient.of("http://localhost:" + backendPort); } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java index cd868dc7ead9..006409230375 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java @@ -16,14 +16,14 @@ public static SmokeTestInstrumentationExtension create() { public void beforeEach(ExtensionContext extensionContext) { Object testInstance = extensionContext.getRequiredTestInstance(); - if (!(testInstance instanceof AbstractSmokeTest)) { + if (!(testInstance instanceof AbstractRemoteTelemetryTest)) { throw new AssertionError( "SmokeTestInstrumentationExtension can only be applied to a subclass of " + "AbstractSmokeTest"); } SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); - ((AbstractSmokeTest) testInstance).configureTelemetryRetriever( + ((AbstractRemoteTelemetryTest) testInstance).configureTelemetryRetriever( smokeTestRunner::setTelemetryRetriever); super.beforeEach(extensionContext); diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java index 5f81fabd7bd0..e087d4d70338 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java @@ -11,7 +11,7 @@ public class SmokeTestRunner extends InstrumentationTestRunner { private static final SmokeTestRunner INSTANCE = new SmokeTestRunner(); - private JavaTelemetryRetriever telemetryRetriever; + private RemoteTelemetryRetriever telemetryRetriever; public static SmokeTestRunner instance() { return INSTANCE; @@ -21,7 +21,7 @@ private SmokeTestRunner() { super(OpenTelemetry.noop()); } - void setTelemetryRetriever(JavaTelemetryRetriever telemetryRetriever) { + void setTelemetryRetriever(RemoteTelemetryRetriever telemetryRetriever) { this.telemetryRetriever = telemetryRetriever; } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 578d3c2b824e..302d6b01837b 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -10,6 +10,7 @@ import static java.util.stream.Collectors.toSet; import static org.assertj.core.api.Assertions.assertThat; +import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; import io.opentelemetry.sdk.logs.data.LogRecordData; import io.opentelemetry.sdk.metrics.data.MetricData; @@ -25,18 +26,21 @@ import java.util.regex.Pattern; import java.util.stream.Stream; import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.RegisterExtension; import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.ToStringConsumer; -public abstract class JavaSmokeTest extends AbstractSmokeTest { +public abstract class JavaSmokeTest extends AbstractRemoteTelemetryTest { private static final Pattern TRACE_ID_PATTERN = Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); protected static final TestContainerManager containerManager = createContainerManager(); - private JavaTelemetryRetriever telemetryRetriever; + private RemoteTelemetryRetriever telemetryRetriever; protected String agentPath = System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path"); + @RegisterExtension static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + protected WebClient client() { return WebClient.of("h1c://localhost:" + containerManager.getTargetMappedPort(8080)); } @@ -72,7 +76,7 @@ protected List getExtraPorts() { @BeforeAll void setUp() { containerManager.startEnvironmentOnce(); - telemetryRetriever = new JavaTelemetryRetriever(containerManager.getBackendMappedPort()); + telemetryRetriever = new RemoteTelemetryRetriever(containerManager.getBackendMappedPort()); } public void runTarget(int jdk, TargetRunner runner) throws Exception { @@ -84,12 +88,14 @@ public void runTarget(int jdk, TargetRunner runner) throws Exception { } } - private Consumer startTarget(int jdk) { + protected Consumer startTarget(int jdk) { return startTarget(String.valueOf(jdk), null, false); } - public Consumer startTarget(String jdk, String serverVersion, boolean windows) { + protected Consumer startTarget(String jdk, String serverVersion, boolean windows) { String targetImage = getTargetImage(jdk, serverVersion, windows); + autoCleanup.deferCleanup(this::stopTarget); + return containerManager.startTarget( targetImage, agentPath, @@ -171,7 +177,7 @@ private static TestContainerManager createContainerManager() { } @Override - public void configureTelemetryRetriever(Consumer action) { + public void configureTelemetryRetriever(Consumer action) { action.accept(telemetryRetriever); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index 6622c2367011..08cd3f3f1bac 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -16,8 +16,8 @@ @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SecurityManagerSmokeTest extends JavaSmokeTest { - @RegisterExtension static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); - @RegisterExtension static final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + @RegisterExtension + static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); @Override protected String getTargetImage(String jdk) { @@ -36,8 +36,7 @@ protected Map getExtraEnv() { @ValueSource(ints = {8, 11, 17, 21, 23}) void securityManagerSmokeTest(int jdk) { startTarget(jdk); - autoCleanup.deferCleanup(this::stopTarget); - - testing.waitAndAssertTraces(trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("test"))); + testing.waitAndAssertTraces( + trace -> trace.hasSpansSatisfyingExactly(span -> span.hasName("test"))); } } From fd9011bdfd9d72ef6b978d90cd44e43c4f4db808 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 18 Sep 2025 14:05:08 +0200 Subject: [PATCH 08/12] unnest --- .../AbstractRemoteTelemetryTest.java | 5 + .../SmokeTestInstrumentationExtension.java | 10 +- .../smoketest/SmokeTestRunner.java | 11 +- .../smoketest/AgentDebugLoggingTest.java | 4 +- .../DeclarativeConfigurationSmokeTest.java | 73 ++++++----- .../smoketest/JavaSmokeTest.java | 11 +- .../smoketest/LogsSmokeTest.java | 13 +- .../smoketest/QuarkusSmokeTest.java | 53 ++++---- .../smoketest/SdkDisabledSmokeTest.java | 25 ++-- .../smoketest/SecurityManagerSmokeTest.java | 1 - .../smoketest/SpringBootSmokeTest.java | 115 ++++++++---------- .../propagation/OtTracePropagationTest.java | 28 ++--- .../propagation/PropagationTest.java | 15 +-- 13 files changed, 169 insertions(+), 195 deletions(-) diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java index dd5925f6a518..b1546da6fe41 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.smoketest; import java.util.function.Consumer; diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java index 006409230375..934277a6d4ac 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.smoketest; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; @@ -23,10 +28,9 @@ public void beforeEach(ExtensionContext extensionContext) { } SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); - ((AbstractRemoteTelemetryTest) testInstance).configureTelemetryRetriever( - smokeTestRunner::setTelemetryRetriever); + ((AbstractRemoteTelemetryTest) testInstance) + .configureTelemetryRetriever(smokeTestRunner::setTelemetryRetriever); super.beforeEach(extensionContext); } } - diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java index e087d4d70338..7e4ef48d3746 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java @@ -1,3 +1,8 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + package io.opentelemetry.smoketest; import io.opentelemetry.api.OpenTelemetry; @@ -26,12 +31,10 @@ void setTelemetryRetriever(RemoteTelemetryRetriever telemetryRetriever) { } @Override - public void beforeTestClass() { - } + public void beforeTestClass() {} @Override - public void afterTestClass() { - } + public void afterTestClass() {} @Override public void clearAllExportedData() { diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java index 45728b98af94..3e77810bfb1e 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java @@ -27,7 +27,7 @@ protected TargetWaitStrategy getWaitStrategy() { @DisplayName("verifies that debug logging is working by checking for a debug log on startup") @Test - void verifyLogging() throws Exception { - runTarget(8, output -> {}); + void verifyLogging() { + startTarget(8); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java index 2c444acab138..3ffb070b3bf8 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -49,44 +49,41 @@ protected TargetWaitStrategy getWaitStrategy() { @ParameterizedTest @ValueSource(ints = {8, 11, 17}) - void springBootSmokeTest(int jdk) throws Exception { - runTarget( - jdk, - output -> { - client().get("/greeting").aggregate().join(); - List traces = waitForTraces(); - assertThat(traces).hasSize(1); + void springBootSmokeTest(int jdk) { + startTarget(jdk); - // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is - // not used, - // because instrumentation_mode=none) - TracesAssert.assertThat(traces) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasResourceSatisfying( - resource -> - resource - .hasAttribute( - ServiceAttributes.SERVICE_NAME, - "declarative-config-smoke-test") - .hasAttribute( - satisfies( - ContainerIncubatingAttributes.CONTAINER_ID, - v -> v.isNotBlank())) - .hasAttribute( - satisfies( - ProcessIncubatingAttributes - .PROCESS_EXECUTABLE_PATH, - v -> v.isNotBlank())) - .hasAttribute( - satisfies( - HostIncubatingAttributes.HOST_NAME, - v -> v.isNotBlank())) - .hasAttribute( - TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME, - "opentelemetry-javaagent")))); - }); + client().get("/greeting").aggregate().join(); + List traces = waitForTraces(); + assertThat(traces).hasSize(1); + + // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is + // not used, + // because instrumentation_mode=none) + TracesAssert.assertThat(traces) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasResourceSatisfying( + resource -> + resource + .hasAttribute( + ServiceAttributes.SERVICE_NAME, + "declarative-config-smoke-test") + .hasAttribute( + satisfies( + ContainerIncubatingAttributes.CONTAINER_ID, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + HostIncubatingAttributes.HOST_NAME, + v -> v.isNotBlank())) + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME, + "opentelemetry-javaagent")))); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 302d6b01837b..9107a4c18e2b 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -79,16 +79,7 @@ void setUp() { telemetryRetriever = new RemoteTelemetryRetriever(containerManager.getBackendMappedPort()); } - public void runTarget(int jdk, TargetRunner runner) throws Exception { - Consumer startTarget = startTarget(jdk); - try { - runner.runInTarget(startTarget); - } finally { - stopTarget(); - } - } - - protected Consumer startTarget(int jdk) { + protected Consumer startTarget(int jdk) { return startTarget(String.valueOf(jdk), null, false); } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java index 9cd060c080c1..3a39fa25e5c9 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java @@ -31,14 +31,11 @@ protected TargetWaitStrategy getWaitStrategy() { @ParameterizedTest @ValueSource(ints = {8, 11, 17}) - void shouldExportLogs(int jdk) throws Exception { - runTarget( - jdk, - output -> { - client().get("/greeting").aggregate().join(); - Collection logs = waitForLogs(); + void shouldExportLogs(int jdk) { + startTarget(jdk); + client().get("/greeting").aggregate().join(); + Collection logs = waitForLogs(); - assertThat(logs).isNotEmpty(); - }); + assertThat(logs).isNotEmpty(); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java index 7564b327df35..870d2efb1c37 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java @@ -38,36 +38,31 @@ protected boolean getSetServiceName() { @ParameterizedTest @ValueSource(ints = {17, 21, 23}) // Quarkus 3.7+ requires Java 17+ void quarkusSmokeTest(int jdk) throws Exception { - runTarget( - jdk, - output -> { - String currentAgentVersion; - try (JarFile agentJar = new JarFile(agentPath)) { - currentAgentVersion = - agentJar - .getManifest() - .getMainAttributes() - .getValue(Attributes.Name.IMPLEMENTATION_VERSION); - } + startTarget(jdk); + String currentAgentVersion; + try (JarFile agentJar = new JarFile(agentPath)) { + currentAgentVersion = + agentJar + .getManifest() + .getMainAttributes() + .getValue(Attributes.Name.IMPLEMENTATION_VERSION); + } - client().get("/hello").aggregate().join(); + client().get("/hello").aggregate().join(); - assertThat(waitForTraces()) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /hello") - .hasResourceSatisfying( - resource -> { - resource - .hasAttribute( - TelemetryIncubatingAttributes - .TELEMETRY_DISTRO_VERSION, - currentAgentVersion) - .hasAttribute( - ServiceAttributes.SERVICE_NAME, "quarkus"); - }))); - }); + assertThat(waitForTraces()) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /hello") + .hasResourceSatisfying( + resource -> { + resource + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, + currentAgentVersion) + .hasAttribute(ServiceAttributes.SERVICE_NAME, "quarkus"); + }))); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java index cc774c723d93..65cddc59a94f 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java @@ -31,20 +31,17 @@ protected Map getExtraEnv() { @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void noopSdkSmokeTest(int jdk) throws Exception { - runTarget( - jdk, - output -> { - String currentAgentVersion = - new JarFile(agentPath) - .getManifest() - .getMainAttributes() - .get(Attributes.Name.IMPLEMENTATION_VERSION) - .toString(); + startTarget(jdk); + String currentAgentVersion = + new JarFile(agentPath) + .getManifest() + .getMainAttributes() + .get(Attributes.Name.IMPLEMENTATION_VERSION) + .toString(); - assertThat(client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); - assertThat(waitForTraces()).isEmpty(); - assertVersionLogged(output, currentAgentVersion); - assertThat(waitForTraces()).isEmpty(); - }); + assertThat(client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); + assertThat(waitForTraces()).isEmpty(); + assertVersionLogged(output, currentAgentVersion); + assertThat(waitForTraces()).isEmpty(); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index 08cd3f3f1bac..e6cf6514fbc8 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -5,7 +5,6 @@ package io.opentelemetry.smoketest; -import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import java.util.Collections; import java.util.Map; diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index fefcb0ce8abb..54759cc4bb50 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -19,12 +19,14 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Consumer; import java.util.jar.Attributes; import java.util.jar.JarFile; import java.util.stream.Collectors; import org.junit.jupiter.api.condition.DisabledIf; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.testcontainers.containers.output.OutputFrame; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SpringBootSmokeTest extends JavaSmokeTest { @@ -54,71 +56,62 @@ protected TargetWaitStrategy getWaitStrategy() { @ParameterizedTest @ValueSource(ints = {8, 11, 17, 21, 23}) void springBootSmokeTest(int jdk) throws Exception { - runTarget( - jdk, - output -> { - String currentAgentVersion; - try (JarFile agentJar = new JarFile(agentPath)) { - currentAgentVersion = - agentJar - .getManifest() - .getMainAttributes() - .getValue(Attributes.Name.IMPLEMENTATION_VERSION); - } + Consumer output = startTarget(jdk); + String currentAgentVersion; + try (JarFile agentJar = new JarFile(agentPath)) { + currentAgentVersion = + agentJar + .getManifest() + .getMainAttributes() + .getValue(Attributes.Name.IMPLEMENTATION_VERSION); + } - var response = client().get("/greeting").aggregate().join(); - assertThat(response.contentUtf8()).isEqualTo("Hi!"); + var response = client().get("/greeting").aggregate().join(); + assertThat(response.contentUtf8()).isEqualTo("Hi!"); - List traces = waitForTraces(); - assertThat(traces) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /greeting") - .hasAttribute( - satisfies( - ThreadIncubatingAttributes.THREAD_ID, a -> a.isNotNull())) - .hasAttribute( - satisfies( - ThreadIncubatingAttributes.THREAD_NAME, - a -> a.isNotBlank())) - .hasResourceSatisfying( - resource -> - resource - .hasAttribute( - TelemetryIncubatingAttributes - .TELEMETRY_DISTRO_VERSION, - currentAgentVersion) - .hasAttribute( - satisfies( - OsIncubatingAttributes.OS_TYPE, - a -> a.isNotNull())) - .hasAttribute(AttributeKey.stringKey("foo"), "bar") - .hasAttribute( - ServiceAttributes.SERVICE_NAME, - "otel-spring-test-app") - .hasAttribute( - ServiceAttributes.SERVICE_VERSION, - "2.10.0-alpha-SNAPSHOT")), - span -> span.hasName("WebController.withSpan"))); + List traces = waitForTraces(); + assertThat(traces) + .hasTracesSatisfyingExactly( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /greeting") + .hasAttribute( + satisfies(ThreadIncubatingAttributes.THREAD_ID, a -> a.isNotNull())) + .hasAttribute( + satisfies( + ThreadIncubatingAttributes.THREAD_NAME, a -> a.isNotBlank())) + .hasResourceSatisfying( + resource -> + resource + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, + currentAgentVersion) + .hasAttribute( + satisfies( + OsIncubatingAttributes.OS_TYPE, a -> a.isNotNull())) + .hasAttribute(AttributeKey.stringKey("foo"), "bar") + .hasAttribute( + ServiceAttributes.SERVICE_NAME, "otel-spring-test-app") + .hasAttribute( + ServiceAttributes.SERVICE_VERSION, + "2.10.0-alpha-SNAPSHOT")), + span -> span.hasName("WebController.withSpan"))); - // Check agent version is logged on startup - assertVersionLogged(output, currentAgentVersion); + // Check agent version is logged on startup + assertVersionLogged(output, currentAgentVersion); - // Check trace IDs are logged via MDC instrumentation - Set loggedTraceIds = getLoggedTraceIds(output); - Set spanTraceIds = - traces.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); - assertThat(loggedTraceIds).isEqualTo(spanTraceIds); + // Check trace IDs are logged via MDC instrumentation + Set loggedTraceIds = getLoggedTraceIds(output); + Set spanTraceIds = traces.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); + assertThat(loggedTraceIds).isEqualTo(spanTraceIds); - // Check JVM metrics are exported - waitAndAssertMetrics( - "io.opentelemetry.runtime-telemetry-java8", - metric -> metric.hasName("jvm.memory.used"), - metric -> metric.hasName("jvm.memory.committed"), - metric -> metric.hasName("jvm.memory.limit"), - metric -> metric.hasName("jvm.memory.used_after_last_gc")); - }); + // Check JVM metrics are exported + waitAndAssertMetrics( + "io.opentelemetry.runtime-telemetry-java8", + metric -> metric.hasName("jvm.memory.used"), + metric -> metric.hasName("jvm.memory.committed"), + metric -> metric.hasName("jvm.memory.limit"), + metric -> metric.hasName("jvm.memory.used_after_last_gc")); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java index 9ec469421f14..0e471b137dff 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java @@ -35,22 +35,18 @@ protected TargetWaitStrategy getWaitStrategy() { } @Test - public void shouldPropagate() throws Exception { - runTarget( - 11, - output -> { - AggregatedHttpResponse response = client().get("/front").aggregate().join(); - List spanData = waitForTraces(); - - Set ids = - spanData.stream().map(s -> s.getTraceId().substring(16)).collect(Collectors.toSet()); - assertThat(ids).hasSize(1); - - var traceId = ids.iterator().next(); - - assertThat(response.contentUtf8()) - .matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); - }); + public void shouldPropagate() { + startTarget(11); + AggregatedHttpResponse response = client().get("/front").aggregate().join(); + List spanData = waitForTraces(); + + Set ids = + spanData.stream().map(s -> s.getTraceId().substring(16)).collect(Collectors.toSet()); + assertThat(ids).hasSize(1); + + var traceId = ids.iterator().next(); + + assertThat(response.contentUtf8()).matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); } @Override diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java index 52f6357a27f6..d4c538718fa2 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java @@ -33,16 +33,13 @@ protected TargetWaitStrategy getWaitStrategy() { @Test public void shouldPropagate() throws Exception { - runTarget( - 11, - output -> { - AggregatedHttpResponse response = client().get("/front").aggregate().join(); - List traces = waitForTraces(); + startTarget(11); + AggregatedHttpResponse response = client().get("/front").aggregate().join(); + List traces = waitForTraces(); - TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(trace -> {}); + TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(trace -> {}); - var traceId = traces.get(0).getTraceId(); - assertThat(response.contentUtf8()).isEqualTo(traceId + ";" + traceId); - }); + var traceId = traces.get(0).getTraceId(); + assertThat(response.contentUtf8()).isEqualTo(traceId + ";" + traceId); } } From 70b83be7854b1f14f8602b612e117cf6c5c56875 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 18 Sep 2025 14:20:58 +0200 Subject: [PATCH 09/12] use tester --- .../DeclarativeConfigurationSmokeTest.java | 51 +++++++-------- .../smoketest/JavaSmokeTest.java | 64 ++++++------------- .../smoketest/LogsSmokeTest.java | 2 +- .../smoketest/QuarkusSmokeTest.java | 27 ++++---- .../smoketest/SdkDisabledSmokeTest.java | 8 ++- .../smoketest/SecurityManagerSmokeTest.java | 2 - .../smoketest/SpringBootSmokeTest.java | 8 +-- .../propagation/OtTracePropagationTest.java | 8 +-- .../propagation/PropagationTest.java | 17 ++--- 9 files changed, 71 insertions(+), 116 deletions(-) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java index 3ffb070b3bf8..aded9f737412 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -53,37 +53,32 @@ void springBootSmokeTest(int jdk) { startTarget(jdk); client().get("/greeting").aggregate().join(); - List traces = waitForTraces(); - assertThat(traces).hasSize(1); // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is // not used, // because instrumentation_mode=none) - TracesAssert.assertThat(traces) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasResourceSatisfying( - resource -> - resource - .hasAttribute( - ServiceAttributes.SERVICE_NAME, - "declarative-config-smoke-test") - .hasAttribute( - satisfies( - ContainerIncubatingAttributes.CONTAINER_ID, - v -> v.isNotBlank())) - .hasAttribute( - satisfies( - ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH, - v -> v.isNotBlank())) - .hasAttribute( - satisfies( - HostIncubatingAttributes.HOST_NAME, - v -> v.isNotBlank())) - .hasAttribute( - TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME, - "opentelemetry-javaagent")))); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasResourceSatisfying( + resource -> + resource + .hasAttribute( + ServiceAttributes.SERVICE_NAME, "declarative-config-smoke-test") + .hasAttribute( + satisfies( + ContainerIncubatingAttributes.CONTAINER_ID, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + ProcessIncubatingAttributes.PROCESS_EXECUTABLE_PATH, + v -> v.isNotBlank())) + .hasAttribute( + satisfies( + HostIncubatingAttributes.HOST_NAME, v -> v.isNotBlank())) + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_NAME, + "opentelemetry-javaagent")))); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 9107a4c18e2b..00e50e582705 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -5,32 +5,32 @@ package io.opentelemetry.smoketest; -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.assertThat; - import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; -import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; -import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.testing.assertj.MetricAssert; -import io.opentelemetry.sdk.trace.data.SpanData; +import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.smoketest.windows.WindowsTestContainerManager; import io.opentelemetry.testing.internal.armeria.client.WebClient; -import java.util.Collection; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.ToStringConsumer; + import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Stream; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.ToStringConsumer; + +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; public abstract class JavaSmokeTest extends AbstractRemoteTelemetryTest { + + @RegisterExtension + public static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); + private static final Pattern TRACE_ID_PATTERN = Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); protected static final TestContainerManager containerManager = createContainerManager(); @@ -79,13 +79,13 @@ void setUp() { telemetryRetriever = new RemoteTelemetryRetriever(containerManager.getBackendMappedPort()); } - protected Consumer startTarget(int jdk) { + protected Consumer startTarget(int jdk) { return startTarget(String.valueOf(jdk), null, false); } protected Consumer startTarget(String jdk, String serverVersion, boolean windows) { String targetImage = getTargetImage(jdk, serverVersion, windows); - autoCleanup.deferCleanup(this::stopTarget); + autoCleanup.deferCleanup(() -> containerManager.stopTarget()); return containerManager.startTarget( targetImage, @@ -113,35 +113,7 @@ protected String[] getCommand() { return null; } - public void cleanup() { - telemetryRetriever.clearTelemetry(); - } - - private void stopTarget() { - containerManager.stopTarget(); - cleanup(); - } - - protected List waitForTraces() { - return telemetryRetriever.waitForTraces(); - } - - @SafeVarargs - @SuppressWarnings("varargs") - protected final void waitAndAssertMetrics( - String instrumentationName, Consumer... assertions) { - MetricsAssert.waitAndAssertMetrics(() -> waitForMetrics(), instrumentationName, assertions); - } - - protected List waitForMetrics() { - return telemetryRetriever.waitForMetrics(); - } - - protected Collection waitForLogs() { - return telemetryRetriever.waitForLogs(); - } - - protected static void assertVersionLogged(Consumer output, String version) { + protected static void assertVersionLogged(Consumer output, String version) { assertThat( logLines(output) .anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version))) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java index 3a39fa25e5c9..57233a9a8d0c 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java @@ -34,7 +34,7 @@ protected TargetWaitStrategy getWaitStrategy() { void shouldExportLogs(int jdk) { startTarget(jdk); client().get("/greeting").aggregate().join(); - Collection logs = waitForLogs(); + Collection logs = testing.logRecords(); assertThat(logs).isNotEmpty(); } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java index 870d2efb1c37..25490efa89c5 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java @@ -50,19 +50,18 @@ void quarkusSmokeTest(int jdk) throws Exception { client().get("/hello").aggregate().join(); - assertThat(waitForTraces()) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /hello") - .hasResourceSatisfying( - resource -> { - resource - .hasAttribute( - TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, - currentAgentVersion) - .hasAttribute(ServiceAttributes.SERVICE_NAME, "quarkus"); - }))); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /hello") + .hasResourceSatisfying( + resource -> { + resource + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, + currentAgentVersion) + .hasAttribute(ServiceAttributes.SERVICE_NAME, "quarkus"); + }))); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java index 65cddc59a94f..41b66d60f333 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java @@ -8,11 +8,13 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import java.util.Map; +import java.util.function.Consumer; import java.util.jar.Attributes; import java.util.jar.JarFile; import org.junit.jupiter.api.condition.DisabledIf; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; +import org.testcontainers.containers.output.OutputFrame; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SdkDisabledSmokeTest extends JavaSmokeTest { @@ -31,7 +33,7 @@ protected Map getExtraEnv() { @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void noopSdkSmokeTest(int jdk) throws Exception { - startTarget(jdk); + Consumer output = startTarget(jdk); String currentAgentVersion = new JarFile(agentPath) .getManifest() @@ -40,8 +42,8 @@ void noopSdkSmokeTest(int jdk) throws Exception { .toString(); assertThat(client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); - assertThat(waitForTraces()).isEmpty(); + assertThat(testing.spans()).isEmpty(); assertVersionLogged(output, currentAgentVersion); - assertThat(waitForTraces()).isEmpty(); + assertThat(testing.spans()).isEmpty(); } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index e6cf6514fbc8..92f4afcc8572 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -15,8 +15,6 @@ @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class SecurityManagerSmokeTest extends JavaSmokeTest { - @RegisterExtension - static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); @Override protected String getTargetImage(String jdk) { diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index 54759cc4bb50..dd4b8dcd3d3f 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -69,8 +69,8 @@ void springBootSmokeTest(int jdk) throws Exception { var response = client().get("/greeting").aggregate().join(); assertThat(response.contentUtf8()).isEqualTo("Hi!"); - List traces = waitForTraces(); - assertThat(traces) + List spans = testing.spans(); + assertThat(spans) .hasTracesSatisfyingExactly( trace -> trace.hasSpansSatisfyingExactly( @@ -103,11 +103,11 @@ void springBootSmokeTest(int jdk) throws Exception { // Check trace IDs are logged via MDC instrumentation Set loggedTraceIds = getLoggedTraceIds(output); - Set spanTraceIds = traces.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); + Set spanTraceIds = spans.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); assertThat(loggedTraceIds).isEqualTo(spanTraceIds); // Check JVM metrics are exported - waitAndAssertMetrics( + testing.waitAndAssertMetrics( "io.opentelemetry.runtime-telemetry-java8", metric -> metric.hasName("jvm.memory.used"), metric -> metric.hasName("jvm.memory.committed"), diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java index 0e471b137dff..e84322425c94 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java @@ -38,13 +38,7 @@ protected TargetWaitStrategy getWaitStrategy() { public void shouldPropagate() { startTarget(11); AggregatedHttpResponse response = client().get("/front").aggregate().join(); - List spanData = waitForTraces(); - - Set ids = - spanData.stream().map(s -> s.getTraceId().substring(16)).collect(Collectors.toSet()); - assertThat(ids).hasSize(1); - - var traceId = ids.iterator().next(); + var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId(); assertThat(response.contentUtf8()).matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java index d4c538718fa2..d70eda30efda 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java @@ -5,17 +5,15 @@ package io.opentelemetry.smoketest.propagation; -import static org.assertj.core.api.Assertions.assertThat; - -import io.opentelemetry.sdk.testing.assertj.TracesAssert; -import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.smoketest.JavaSmokeTest; import io.opentelemetry.smoketest.TargetWaitStrategy; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; -import java.time.Duration; -import java.util.List; import org.junit.jupiter.api.Test; +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; + public abstract class PropagationTest extends JavaSmokeTest { @Override @@ -32,14 +30,11 @@ protected TargetWaitStrategy getWaitStrategy() { } @Test - public void shouldPropagate() throws Exception { + public void shouldPropagate() { startTarget(11); AggregatedHttpResponse response = client().get("/front").aggregate().join(); - List traces = waitForTraces(); - - TracesAssert.assertThat(traces).hasTracesSatisfyingExactly(trace -> {}); - var traceId = traces.get(0).getTraceId(); + var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId(); assertThat(response.contentUtf8()).isEqualTo(traceId + ";" + traceId); } } From 700661ce13b1918e879fcd56d3f55c8dc36ded24 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 18 Sep 2025 14:21:42 +0200 Subject: [PATCH 10/12] use tester --- .../DeclarativeConfigurationSmokeTest.java | 3 --- .../smoketest/JavaSmokeTest.java | 21 +++++++++---------- .../smoketest/QuarkusSmokeTest.java | 2 -- .../smoketest/SecurityManagerSmokeTest.java | 2 -- .../smoketest/SpringBootSmokeTest.java | 2 +- .../propagation/OtTracePropagationTest.java | 6 +----- .../propagation/PropagationTest.java | 7 +++---- 7 files changed, 15 insertions(+), 28 deletions(-) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java index aded9f737412..48c52e42e292 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -5,11 +5,8 @@ package io.opentelemetry.smoketest; -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import io.opentelemetry.sdk.testing.assertj.TracesAssert; -import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.semconv.ServiceAttributes; import io.opentelemetry.semconv.incubating.ContainerIncubatingAttributes; import io.opentelemetry.semconv.incubating.HostIncubatingAttributes; diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 00e50e582705..7e122a36552f 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -5,26 +5,25 @@ package io.opentelemetry.smoketest; +import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; + import io.opentelemetry.instrumentation.testing.internal.AutoCleanupExtension; import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import io.opentelemetry.smoketest.windows.WindowsTestContainerManager; import io.opentelemetry.testing.internal.armeria.client.WebClient; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.testcontainers.containers.output.OutputFrame; -import org.testcontainers.containers.output.ToStringConsumer; - import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Stream; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.stream.Collectors.toSet; -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.ToStringConsumer; public abstract class JavaSmokeTest extends AbstractRemoteTelemetryTest { @@ -113,7 +112,7 @@ protected String[] getCommand() { return null; } - protected static void assertVersionLogged(Consumer output, String version) { + protected static void assertVersionLogged(Consumer output, String version) { assertThat( logLines(output) .anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version))) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java index 25490efa89c5..9f7d3ea00946 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java @@ -5,8 +5,6 @@ package io.opentelemetry.smoketest; -import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; - import io.opentelemetry.semconv.ServiceAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; import java.time.Duration; diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java index 92f4afcc8572..1b9a0070775b 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -5,11 +5,9 @@ package io.opentelemetry.smoketest; -import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import java.util.Collections; import java.util.Map; import org.junit.jupiter.api.condition.DisabledIf; -import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index dd4b8dcd3d3f..033e97bf2d1c 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -107,7 +107,7 @@ void springBootSmokeTest(int jdk) throws Exception { assertThat(loggedTraceIds).isEqualTo(spanTraceIds); // Check JVM metrics are exported - testing.waitAndAssertMetrics( + testing.waitAndAssertMetrics( "io.opentelemetry.runtime-telemetry-java8", metric -> metric.hasName("jvm.memory.used"), metric -> metric.hasName("jvm.memory.committed"), diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java index e84322425c94..4596ab8898a6 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java @@ -7,15 +7,11 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.smoketest.JavaSmokeTest; import io.opentelemetry.smoketest.TargetWaitStrategy; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; import java.time.Duration; -import java.util.List; import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; @@ -38,7 +34,7 @@ protected TargetWaitStrategy getWaitStrategy() { public void shouldPropagate() { startTarget(11); AggregatedHttpResponse response = client().get("/front").aggregate().join(); - var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId(); + var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId(); assertThat(response.contentUtf8()).matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java index d70eda30efda..ab4ef67aa6e9 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/PropagationTest.java @@ -5,14 +5,13 @@ package io.opentelemetry.smoketest.propagation; +import static org.assertj.core.api.Assertions.assertThat; + import io.opentelemetry.smoketest.JavaSmokeTest; import io.opentelemetry.smoketest.TargetWaitStrategy; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; -import org.junit.jupiter.api.Test; - import java.time.Duration; - -import static org.assertj.core.api.Assertions.assertThat; +import org.junit.jupiter.api.Test; public abstract class PropagationTest extends JavaSmokeTest { From ec3eb25a7f7611ee3ca0bfc15137145465d6b036 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Thu, 18 Sep 2025 15:12:59 +0200 Subject: [PATCH 11/12] fix --- .../smoketest/propagation/OtTracePropagationTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java index 4596ab8898a6..698f5980b0a6 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/OtTracePropagationTest.java @@ -34,7 +34,7 @@ protected TargetWaitStrategy getWaitStrategy() { public void shouldPropagate() { startTarget(11); AggregatedHttpResponse response = client().get("/front").aggregate().join(); - var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId(); + var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId().substring(16); assertThat(response.contentUtf8()).matches("[0-9a-f]{16}" + traceId + ";[0]{16}" + traceId); } From 8421f51ab43abd0a61bd8b82b7e359d4d1f8bd93 Mon Sep 17 00:00:00 2001 From: Lauri Tulmin Date: Fri, 19 Sep 2025 12:31:14 +0300 Subject: [PATCH 12/12] review --- .../AbstractRemoteTelemetryTest.java | 14 --- .../GroovyTestTelemetryRetriever.java | 88 +++++++++++++ .../smoketest/RemoteTelemetryRetriever.java | 117 ------------------ .../SmokeTestInstrumentationExtension.java | 29 ++++- .../smoketest/SmokeTestRunner.java | 8 +- .../opentelemetry/smoketest/TargetRunner.java | 14 --- .../smoketest/TelemetryRetriever.java | 85 ++++++++----- .../smoketest/TelemetryRetrieverProvider.java | 14 +++ .../IbmHttpsUrlConnectionTest.groovy | 2 +- .../opentelemetry/smoketest/SmokeTest.groovy | 4 +- .../DeclarativeConfigurationSmokeTest.java | 3 +- .../smoketest/JavaSmokeTest.java | 14 +-- .../smoketest/SpringBootSmokeTest.java | 57 ++++----- .../testing/InstrumentationTestRunner.java | 21 +++- .../testing/junit/MetricsAssert.java | 53 -------- 15 files changed, 247 insertions(+), 276 deletions(-) delete mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java create mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/GroovyTestTelemetryRetriever.java delete mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java delete mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java create mode 100644 smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetrieverProvider.java delete mode 100644 testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java deleted file mode 100644 index b1546da6fe41..000000000000 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/AbstractRemoteTelemetryTest.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest; - -import java.util.function.Consumer; -import org.junit.jupiter.api.TestInstance; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public abstract class AbstractRemoteTelemetryTest { - public abstract void configureTelemetryRetriever(Consumer action); -} diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/GroovyTestTelemetryRetriever.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/GroovyTestTelemetryRetriever.java new file mode 100644 index 000000000000..ac6d8b1d8498 --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/GroovyTestTelemetryRetriever.java @@ -0,0 +1,88 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.protobuf.GeneratedMessage; +import com.google.protobuf.util.JsonFormat; +import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest; +import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; +import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; +import io.opentelemetry.testing.internal.armeria.client.WebClient; +import java.util.Collection; +import java.util.concurrent.TimeUnit; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + +public class GroovyTestTelemetryRetriever { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + final WebClient client; + + GroovyTestTelemetryRetriever(int backendPort) { + client = WebClient.of("http://localhost:" + backendPort); + } + + void clearTelemetry() { + client.get("/clear").aggregate().join(); + } + + Collection waitForTraces() { + return waitForTelemetry("get-traces", ExportTraceServiceRequest::newBuilder); + } + + Collection waitForMetrics() { + return waitForTelemetry("get-metrics", ExportMetricsServiceRequest::newBuilder); + } + + Collection waitForLogs() { + return waitForTelemetry("get-logs", ExportLogsServiceRequest::newBuilder); + } + + @SuppressWarnings({"unchecked", "InterruptedExceptionSwallowed"}) + private > + Collection waitForTelemetry(String path, Supplier builderConstructor) { + try { + String content = waitForContent(path); + + return StreamSupport.stream(OBJECT_MAPPER.readTree(content).spliterator(), false) + .map( + jsonNode -> { + B builder = builderConstructor.get(); + // TODO: Register parser into object mapper to avoid de -> re -> deserialize. + try { + String json = OBJECT_MAPPER.writeValueAsString(jsonNode); + JsonFormat.parser().merge(json, builder); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return (T) builder.build(); + }) + .collect(Collectors.toList()); + } catch (Exception e) { + throw new IllegalStateException(e); + } + } + + @SuppressWarnings("SystemOut") + private String waitForContent(String path) throws InterruptedException { + long previousSize = 0; + long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30); + String content = "[]"; + while (System.currentTimeMillis() < deadline) { + content = client.get(path).aggregate().join().contentUtf8(); + if (content.length() > 2 && content.length() == previousSize) { + break; + } + previousSize = content.length(); + System.out.println("Current content size $previousSize"); + TimeUnit.MILLISECONDS.sleep(500); + } + + return content; + } +} diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java deleted file mode 100644 index cef1d82eb463..000000000000 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/RemoteTelemetryRetriever.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest; - -import io.opentelemetry.instrumentation.testing.internal.TelemetryConverter; -import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.testing.internal.armeria.client.WebClient; -import io.opentelemetry.testing.internal.jackson.core.JsonProcessingException; -import io.opentelemetry.testing.internal.jackson.databind.ObjectMapper; -import io.opentelemetry.testing.internal.proto.collector.logs.v1.ExportLogsServiceRequest; -import io.opentelemetry.testing.internal.proto.collector.metrics.v1.ExportMetricsServiceRequest; -import io.opentelemetry.testing.internal.proto.collector.trace.v1.ExportTraceServiceRequest; -import io.opentelemetry.testing.internal.protobuf.GeneratedMessage; -import io.opentelemetry.testing.internal.protobuf.InvalidProtocolBufferException; -import io.opentelemetry.testing.internal.protobuf.util.JsonFormat; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.TimeUnit; -import java.util.function.Function; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class RemoteTelemetryRetriever { - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - private final WebClient client; - - public RemoteTelemetryRetriever(int backendPort) { - client = WebClient.of("http://localhost:" + backendPort); - } - - public void clearTelemetry() { - client.get("/clear").aggregate().join(); - } - - public List waitForTraces() { - Collection requests = - waitForTelemetry("get-traces", ExportTraceServiceRequest::newBuilder); - return TelemetryConverter.getSpanData( - convert(requests, ExportTraceServiceRequest::getResourceSpansList)); - } - - public List waitForMetrics() { - Collection requests = - waitForTelemetry("get-metrics", ExportMetricsServiceRequest::newBuilder); - return TelemetryConverter.getMetricsData( - convert(requests, ExportMetricsServiceRequest::getResourceMetricsList)); - } - - public List waitForLogs() { - Collection requests = - waitForTelemetry("get-logs", ExportLogsServiceRequest::newBuilder); - return TelemetryConverter.getLogRecordData( - convert(requests, ExportLogsServiceRequest::getResourceLogsList)); - } - - private static List convert(Collection items, Function> converter) { - return items.stream() - .flatMap(item -> converter.apply(item).stream()) - .collect(Collectors.toList()); - } - - @SuppressWarnings({"unchecked", "rawtypes"}) - private - Collection waitForTelemetry(String path, Supplier builderConstructor) { - try { - return OBJECT_MAPPER - .readTree(waitForContent(path)) - .valueStream() - .map( - jsonNode -> { - B builder = builderConstructor.get(); - // TODO: Register parser into object mapper to avoid de -> re -> deserialize. - try { - JsonFormat.parser().merge(OBJECT_MAPPER.writeValueAsString(jsonNode), builder); - return (T) builder.build(); - } catch (InvalidProtocolBufferException | JsonProcessingException e) { - throw new IllegalStateException(e); - } - }) - .collect(Collectors.toList()); - } catch (InterruptedException | JsonProcessingException e) { - throw new IllegalStateException(e); - } - } - - @SuppressWarnings("SystemOut") - private String waitForContent(String path) throws InterruptedException { - long previousSize = 0; - long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30); - String content = "[]"; - while (System.currentTimeMillis() < deadline) { - content = client.get(path).aggregate().join().contentUtf8(); - if (content.length() > 2 && content.length() == previousSize) { - break; - } - - previousSize = content.length(); - System.out.println("Current content size " + previousSize); - TimeUnit.MILLISECONDS.sleep(500); - } - - if ("true".equals(System.getenv("debug"))) { - System.out.println(content); - } - - return content; - } - - public final WebClient getClient() { - return client; - } -} diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java index 934277a6d4ac..8002f7775560 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java @@ -8,6 +8,27 @@ import io.opentelemetry.instrumentation.testing.junit.InstrumentationExtension; import org.junit.jupiter.api.extension.ExtensionContext; +/** + * JUnit 5 extension for writing smoke tests that use a {@link TelemetryRetriever} to retrieve + * telemetry data from the fake backend. + * + *

Example usage: + * + *

+ *   class MySmokeTest implements TelemetryRetrieverProvider {
+ *     {@literal @}RegisterExtension
+ *     static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create();
+ *
+ *     {@literal @}Test
+ *     void test() {
+ *       // test code ...
+ *
+ *       var spans = testing.spans();
+ *       // assertions on collected spans ...
+ *     }
+ *   }
+ * 
+ */ public class SmokeTestInstrumentationExtension extends InstrumentationExtension { private SmokeTestInstrumentationExtension() { super(SmokeTestRunner.instance()); @@ -21,15 +42,15 @@ public static SmokeTestInstrumentationExtension create() { public void beforeEach(ExtensionContext extensionContext) { Object testInstance = extensionContext.getRequiredTestInstance(); - if (!(testInstance instanceof AbstractRemoteTelemetryTest)) { + if (!(testInstance instanceof TelemetryRetrieverProvider)) { throw new AssertionError( "SmokeTestInstrumentationExtension can only be applied to a subclass of " - + "AbstractSmokeTest"); + + "TelemetryRetrieverProvider"); } SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); - ((AbstractRemoteTelemetryTest) testInstance) - .configureTelemetryRetriever(smokeTestRunner::setTelemetryRetriever); + smokeTestRunner.setTelemetryRetriever( + ((TelemetryRetrieverProvider) testInstance).getTelemetryRetriever()); super.beforeEach(extensionContext); } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java index 7e4ef48d3746..935866770cba 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java @@ -12,11 +12,15 @@ import io.opentelemetry.sdk.trace.data.SpanData; import java.util.List; +/** + * An implementation of {@link InstrumentationTestRunner} that uses {@link TelemetryRetriever} to + * fetch traces, metrics and logs from the fake backend. + */ public class SmokeTestRunner extends InstrumentationTestRunner { private static final SmokeTestRunner INSTANCE = new SmokeTestRunner(); - private RemoteTelemetryRetriever telemetryRetriever; + private TelemetryRetriever telemetryRetriever; public static SmokeTestRunner instance() { return INSTANCE; @@ -26,7 +30,7 @@ private SmokeTestRunner() { super(OpenTelemetry.noop()); } - void setTelemetryRetriever(RemoteTelemetryRetriever telemetryRetriever) { + void setTelemetryRetriever(TelemetryRetriever telemetryRetriever) { this.telemetryRetriever = telemetryRetriever; } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java deleted file mode 100644 index aa6f04e7c99f..000000000000 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TargetRunner.java +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.smoketest; - -import java.util.function.Consumer; -import org.testcontainers.containers.output.OutputFrame; - -@FunctionalInterface -public interface TargetRunner { - void runInTarget(Consumer startTarget) throws Exception; -} diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java index b737d27c5b04..32ad80ca2763 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java @@ -5,65 +5,85 @@ package io.opentelemetry.smoketest; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.protobuf.GeneratedMessage; -import com.google.protobuf.util.JsonFormat; -import io.opentelemetry.proto.collector.logs.v1.ExportLogsServiceRequest; -import io.opentelemetry.proto.collector.metrics.v1.ExportMetricsServiceRequest; -import io.opentelemetry.proto.collector.trace.v1.ExportTraceServiceRequest; +import io.opentelemetry.instrumentation.testing.internal.TelemetryConverter; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.trace.data.SpanData; import io.opentelemetry.testing.internal.armeria.client.WebClient; +import io.opentelemetry.testing.internal.jackson.core.JsonProcessingException; +import io.opentelemetry.testing.internal.jackson.databind.ObjectMapper; +import io.opentelemetry.testing.internal.proto.collector.logs.v1.ExportLogsServiceRequest; +import io.opentelemetry.testing.internal.proto.collector.metrics.v1.ExportMetricsServiceRequest; +import io.opentelemetry.testing.internal.proto.collector.trace.v1.ExportTraceServiceRequest; +import io.opentelemetry.testing.internal.protobuf.GeneratedMessage; +import io.opentelemetry.testing.internal.protobuf.InvalidProtocolBufferException; +import io.opentelemetry.testing.internal.protobuf.util.JsonFormat; import java.util.Collection; +import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; -import java.util.stream.StreamSupport; public class TelemetryRetriever { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private final WebClient client; - final WebClient client; - - TelemetryRetriever(int backendPort) { + public TelemetryRetriever(int backendPort) { client = WebClient.of("http://localhost:" + backendPort); } - void clearTelemetry() { + public void clearTelemetry() { client.get("/clear").aggregate().join(); } - Collection waitForTraces() { - return waitForTelemetry("get-traces", ExportTraceServiceRequest::newBuilder); + public List waitForTraces() { + Collection requests = + waitForTelemetry("get-traces", ExportTraceServiceRequest::newBuilder); + return TelemetryConverter.getSpanData( + convert(requests, ExportTraceServiceRequest::getResourceSpansList)); + } + + public List waitForMetrics() { + Collection requests = + waitForTelemetry("get-metrics", ExportMetricsServiceRequest::newBuilder); + return TelemetryConverter.getMetricsData( + convert(requests, ExportMetricsServiceRequest::getResourceMetricsList)); } - Collection waitForMetrics() { - return waitForTelemetry("get-metrics", ExportMetricsServiceRequest::newBuilder); + public List waitForLogs() { + Collection requests = + waitForTelemetry("get-logs", ExportLogsServiceRequest::newBuilder); + return TelemetryConverter.getLogRecordData( + convert(requests, ExportLogsServiceRequest::getResourceLogsList)); } - Collection waitForLogs() { - return waitForTelemetry("get-logs", ExportLogsServiceRequest::newBuilder); + private static List convert(Collection items, Function> converter) { + return items.stream() + .flatMap(item -> converter.apply(item).stream()) + .collect(Collectors.toList()); } - @SuppressWarnings({"unchecked", "InterruptedExceptionSwallowed"}) - private > + @SuppressWarnings({"unchecked", "rawtypes"}) + private Collection waitForTelemetry(String path, Supplier builderConstructor) { try { - String content = waitForContent(path); - - return StreamSupport.stream(OBJECT_MAPPER.readTree(content).spliterator(), false) + return OBJECT_MAPPER + .readTree(waitForContent(path)) + .valueStream() .map( jsonNode -> { B builder = builderConstructor.get(); // TODO: Register parser into object mapper to avoid de -> re -> deserialize. try { - String json = OBJECT_MAPPER.writeValueAsString(jsonNode); - JsonFormat.parser().merge(json, builder); - } catch (Exception e) { + JsonFormat.parser().merge(OBJECT_MAPPER.writeValueAsString(jsonNode), builder); + return (T) builder.build(); + } catch (InvalidProtocolBufferException | JsonProcessingException e) { throw new IllegalStateException(e); } - return (T) builder.build(); }) .collect(Collectors.toList()); - } catch (Exception e) { + } catch (InterruptedException | JsonProcessingException e) { throw new IllegalStateException(e); } } @@ -78,11 +98,20 @@ private String waitForContent(String path) throws InterruptedException { if (content.length() > 2 && content.length() == previousSize) { break; } + previousSize = content.length(); - System.out.println("Current content size $previousSize"); + System.out.println("Current content size " + previousSize); TimeUnit.MILLISECONDS.sleep(500); } + if ("true".equals(System.getenv("debug"))) { + System.out.println(content); + } + return content; } + + public final WebClient getClient() { + return client; + } } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetrieverProvider.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetrieverProvider.java new file mode 100644 index 000000000000..ba9a9715db08 --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetrieverProvider.java @@ -0,0 +1,14 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +/** + * Provides a {@link TelemetryRetriever} instance. Tests using {@link + * SmokeTestInstrumentationExtension} must implement this interface. + */ +public interface TelemetryRetrieverProvider { + TelemetryRetriever getTelemetryRetriever(); +} diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/IbmHttpsUrlConnectionTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/IbmHttpsUrlConnectionTest.groovy index e9e5f2c89f8a..cfba01a7d654 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/IbmHttpsUrlConnectionTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/IbmHttpsUrlConnectionTest.groovy @@ -47,7 +47,7 @@ class IbmHttpsUrlConnectionTest extends Specification { .withLogConsumer(new Slf4jLogConsumer(logger)) backend.start() - def telemetryRetriever = new TelemetryRetriever(backend.getMappedPort(BACKEND_PORT)) + def telemetryRetriever = new GroovyTestTelemetryRetriever(backend.getMappedPort(BACKEND_PORT)) GenericContainer target = new GenericContainer<>(DockerImageName.parse("ibmjava:8-sdk")) diff --git a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy index d2f6f53e613f..931d7998ce71 100644 --- a/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy +++ b/smoke-tests/src/test/groovy/io/opentelemetry/smoketest/SmokeTest.groovy @@ -28,7 +28,7 @@ abstract class SmokeTest extends Specification { protected static final TestContainerManager containerManager = createContainerManager() @Shared - private TelemetryRetriever telemetryRetriever + private GroovyTestTelemetryRetriever telemetryRetriever @Shared protected String agentPath = System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path") @@ -75,7 +75,7 @@ abstract class SmokeTest extends Specification { def setupSpec() { containerManager.startEnvironmentOnce() - telemetryRetriever = new TelemetryRetriever(containerManager.getBackendMappedPort()) + telemetryRetriever = new GroovyTestTelemetryRetriever(containerManager.getBackendMappedPort()) } def startTarget(int jdk) { diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java index 48c52e42e292..608ab18d2763 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -52,8 +52,7 @@ void springBootSmokeTest(int jdk) { client().get("/greeting").aggregate().join(); // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is - // not used, - // because instrumentation_mode=none) + // not used, because instrumentation_mode=none) testing.waitAndAssertTraces( trace -> trace.hasSpansSatisfyingExactly( diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java index 7e122a36552f..88ebff9a2e72 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java @@ -25,7 +25,7 @@ import org.testcontainers.containers.output.OutputFrame; import org.testcontainers.containers.output.ToStringConsumer; -public abstract class JavaSmokeTest extends AbstractRemoteTelemetryTest { +public abstract class JavaSmokeTest implements TelemetryRetrieverProvider { @RegisterExtension public static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create(); @@ -33,7 +33,7 @@ public abstract class JavaSmokeTest extends AbstractRemoteTelemetryTest { private static final Pattern TRACE_ID_PATTERN = Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); protected static final TestContainerManager containerManager = createContainerManager(); - private RemoteTelemetryRetriever telemetryRetriever; + private static TelemetryRetriever telemetryRetriever; protected String agentPath = System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path"); @@ -73,9 +73,9 @@ protected List getExtraPorts() { } @BeforeAll - void setUp() { + static void setUp() { containerManager.startEnvironmentOnce(); - telemetryRetriever = new RemoteTelemetryRetriever(containerManager.getBackendMappedPort()); + telemetryRetriever = new TelemetryRetriever(containerManager.getBackendMappedPort()); } protected Consumer startTarget(int jdk) { @@ -124,7 +124,7 @@ private static Stream logLines(Consumer output) { } protected static Set getLoggedTraceIds(Consumer output) { - return logLines(output).flatMap(l -> findTraceId(l)).collect(toSet()); + return logLines(output).flatMap(JavaSmokeTest::findTraceId).collect(toSet()); } private static Stream findTraceId(String log) { @@ -139,7 +139,7 @@ private static TestContainerManager createContainerManager() { } @Override - public void configureTelemetryRetriever(Consumer action) { - action.accept(telemetryRetriever); + public TelemetryRetriever getTelemetryRetriever() { + return telemetryRetriever; } } diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java index 033e97bf2d1c..0029c10d0765 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -7,7 +7,6 @@ import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.satisfies; -import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; import io.opentelemetry.api.common.AttributeKey; import io.opentelemetry.sdk.trace.data.SpanData; @@ -69,41 +68,39 @@ void springBootSmokeTest(int jdk) throws Exception { var response = client().get("/greeting").aggregate().join(); assertThat(response.contentUtf8()).isEqualTo("Hi!"); - List spans = testing.spans(); - assertThat(spans) - .hasTracesSatisfyingExactly( - trace -> - trace.hasSpansSatisfyingExactly( - span -> - span.hasName("GET /greeting") - .hasAttribute( - satisfies(ThreadIncubatingAttributes.THREAD_ID, a -> a.isNotNull())) - .hasAttribute( - satisfies( - ThreadIncubatingAttributes.THREAD_NAME, a -> a.isNotBlank())) - .hasResourceSatisfying( - resource -> - resource - .hasAttribute( - TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, - currentAgentVersion) - .hasAttribute( - satisfies( - OsIncubatingAttributes.OS_TYPE, a -> a.isNotNull())) - .hasAttribute(AttributeKey.stringKey("foo"), "bar") - .hasAttribute( - ServiceAttributes.SERVICE_NAME, "otel-spring-test-app") - .hasAttribute( - ServiceAttributes.SERVICE_VERSION, - "2.10.0-alpha-SNAPSHOT")), - span -> span.hasName("WebController.withSpan"))); + testing.waitAndAssertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasName("GET /greeting") + .hasAttribute( + satisfies(ThreadIncubatingAttributes.THREAD_ID, a -> a.isNotNull())) + .hasAttribute( + satisfies(ThreadIncubatingAttributes.THREAD_NAME, a -> a.isNotBlank())) + .hasResourceSatisfying( + resource -> + resource + .hasAttribute( + TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, + currentAgentVersion) + .hasAttribute( + satisfies( + OsIncubatingAttributes.OS_TYPE, a -> a.isNotNull())) + .hasAttribute(AttributeKey.stringKey("foo"), "bar") + .hasAttribute( + ServiceAttributes.SERVICE_NAME, "otel-spring-test-app") + .hasAttribute( + ServiceAttributes.SERVICE_VERSION, + "2.10.0-alpha-SNAPSHOT")), + span -> span.hasName("WebController.withSpan"))); // Check agent version is logged on startup assertVersionLogged(output, currentAgentVersion); // Check trace IDs are logged via MDC instrumentation Set loggedTraceIds = getLoggedTraceIds(output); - Set spanTraceIds = spans.stream().map(t -> t.getTraceId()).collect(Collectors.toSet()); + List spans = testing.spans(); + Set spanTraceIds = spans.stream().map(SpanData::getTraceId).collect(Collectors.toSet()); assertThat(loggedTraceIds).isEqualTo(spanTraceIds); // Check JVM metrics are exported diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java index d9dbafbc38cb..b63bb7bd3550 100644 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java +++ b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/InstrumentationTestRunner.java @@ -13,7 +13,6 @@ import io.opentelemetry.api.common.AttributeType; import io.opentelemetry.api.internal.InternalAttributeKeyImpl; import io.opentelemetry.api.trace.SpanKind; -import io.opentelemetry.instrumentation.testing.junit.MetricsAssert; import io.opentelemetry.instrumentation.testing.util.TelemetryDataUtil; import io.opentelemetry.instrumentation.testing.util.ThrowingRunnable; import io.opentelemetry.instrumentation.testing.util.ThrowingSupplier; @@ -28,6 +27,7 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -35,6 +35,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.function.Consumer; +import java.util.stream.Collectors; import javax.annotation.Nullable; import org.assertj.core.api.ListAssert; import org.awaitility.core.ConditionFactory; @@ -185,7 +186,17 @@ public final void waitAndAssertMetrics( public final void waitAndAssertMetrics( String instrumentationName, Consumer... assertions) { awaitUntilAsserted( - () -> MetricsAssert.assertMetrics(getExportedMetrics(), instrumentationName, assertions)); + () -> { + Collection metrics = instrumentationMetrics(instrumentationName); + assertThat(metrics).isNotEmpty(); + for (int i = 0; i < assertions.length; i++) { + int index = i; + assertThat(metrics) + .describedAs( + "Metrics for instrumentation %s and assertion %d", instrumentationName, index) + .anySatisfy(metric -> assertions[index].accept(assertThat(metric))); + } + }); if (Boolean.getBoolean("collectMetadata")) { collectEmittedMetrics(getExportedMetrics()); @@ -235,6 +246,12 @@ public final List waitForLogRecords(int numberOfLogRecords) { return getExportedLogRecords(); } + private List instrumentationMetrics(String instrumentationName) { + return getExportedMetrics().stream() + .filter(m -> m.getInstrumentationScopeInfo().getName().equals(instrumentationName)) + .collect(Collectors.toList()); + } + /** * Runs the provided {@code callback} inside the scope of an INTERNAL span with name {@code * spanName}. diff --git a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java b/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java deleted file mode 100644 index 79ecef1396bf..000000000000 --- a/testing-common/src/main/java/io/opentelemetry/instrumentation/testing/junit/MetricsAssert.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.instrumentation.testing.junit; - -import static io.opentelemetry.sdk.testing.assertj.OpenTelemetryAssertions.assertThat; -import static org.awaitility.Awaitility.await; - -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.testing.assertj.MetricAssert; -import java.util.Collection; -import java.util.List; -import java.util.function.Consumer; -import java.util.function.Supplier; -import java.util.stream.Collectors; - -public class MetricsAssert { - - @SafeVarargs - public static void waitAndAssertMetrics( - Supplier> metricData, - String instrumentationName, - Consumer... assertions) { - await().untilAsserted(() -> assertMetrics(metricData.get(), instrumentationName, assertions)); - } - - @SafeVarargs - public static void assertMetrics( - List metricData, - String instrumentationName, - Consumer... assertions) { - Collection metrics = instrumentationMetrics(instrumentationName, metricData); - assertThat(metrics).isNotEmpty(); - for (int i = 0; i < assertions.length; i++) { - int index = i; - assertThat(metrics) - .describedAs( - "Metrics for instrumentation %s and assertion %d", instrumentationName, index) - .anySatisfy(metric -> assertions[index].accept(assertThat(metric))); - } - } - - private static List instrumentationMetrics( - String instrumentationName, List metrics) { - return metrics.stream() - .filter(m -> m.getInstrumentationScopeInfo().getName().equals(instrumentationName)) - .collect(Collectors.toList()); - } - - private MetricsAssert() {} -}