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 8002f7775560..07f7bbbedaf5 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestInstrumentationExtension.java @@ -5,7 +5,20 @@ package io.opentelemetry.smoketest; +import com.google.errorprone.annotations.CanIgnoreReturnValue; +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 java.io.IOException; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import javax.annotation.Nullable; import org.junit.jupiter.api.extension.ExtensionContext; /** @@ -15,12 +28,14 @@ *

Example usage: * *

- *   class MySmokeTest implements TelemetryRetrieverProvider {
+ *   class MySmokeTest {
  *     {@literal @}RegisterExtension
- *     static final InstrumentationExtension testing = SmokeTestInstrumentationExtension.create();
+ *     static final SmokeTestInstrumentationExtension testing = SmokeTestInstrumentationExtension.springBoot("version").build();
  *
- *     {@literal @}Test
- *     void test() {
+ *     {@literal @}ParameterizedTest
+ *     {@literal @}ValueSource(ints = {8, 11, 17})
+ *     void test(int jdk) throws Exception {
+ *     SmokeTestOutput output = testing.start(jdk);
  *       // test code ...
  *
  *       var spans = testing.spans();
@@ -29,29 +44,225 @@
  *   }
  * 
*/ -public class SmokeTestInstrumentationExtension extends InstrumentationExtension { - private SmokeTestInstrumentationExtension() { - super(SmokeTestRunner.instance()); +public class SmokeTestInstrumentationExtension extends InstrumentationExtension + implements TelemetryRetrieverProvider { + + private final TestContainerManager containerManager = createContainerManager(); + + private TelemetryRetriever telemetryRetriever; + + private final String agentPath = + System.getProperty("io.opentelemetry.smoketest.agent.shadowJar.path"); + + private final AutoCleanupExtension autoCleanup = AutoCleanupExtension.create(); + + @FunctionalInterface + public interface GetTargetImage { + String getTargetImage(String jdk, String serverVersion, boolean windows); + } + + private final GetTargetImage getTargetImage; + + private final String[] command; + private final String jvmArgsEnvVarName; + private final boolean setServiceName; + private final Map extraEnv; + private final List extraResources; + private final TargetWaitStrategy waitStrategy; + private final List extraPorts; + private final Duration telemetryTimeout; + + private SmokeTestInstrumentationExtension( + GetTargetImage getTargetImage, + String[] command, + String jvmArgsEnvVarName, + boolean setServiceName, + Map extraEnv, + List extraResources, + TargetWaitStrategy waitStrategy, + List extraPorts, + Duration telemetryTimeout) { + super(new SmokeTestRunner()); + this.getTargetImage = getTargetImage; + this.command = command; + this.jvmArgsEnvVarName = jvmArgsEnvVarName; + this.setServiceName = setServiceName; + this.extraEnv = extraEnv; + this.extraResources = extraResources; + this.waitStrategy = waitStrategy; + this.extraPorts = extraPorts; + this.telemetryTimeout = telemetryTimeout; } - public static SmokeTestInstrumentationExtension create() { - return new SmokeTestInstrumentationExtension(); + public WebClient client() { + return WebClient.of("h1c://localhost:" + containerManager.getTargetMappedPort(8080)); + } + + @Override + public void beforeAll(ExtensionContext context) throws Exception { + containerManager.startEnvironmentOnce(); + telemetryRetriever = + new TelemetryRetriever(containerManager.getBackendMappedPort(), telemetryTimeout); + super.beforeAll(context); } @Override public void beforeEach(ExtensionContext extensionContext) { - Object testInstance = extensionContext.getRequiredTestInstance(); + SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); + smokeTestRunner.setTelemetryRetriever(getTelemetryRetriever()); + super.beforeEach(extensionContext); + } + + @Override + public void afterEach(ExtensionContext context) throws Exception { + autoCleanup.afterEach(context); + super.afterEach(context); + } - if (!(testInstance instanceof TelemetryRetrieverProvider)) { - throw new AssertionError( - "SmokeTestInstrumentationExtension can only be applied to a subclass of " - + "TelemetryRetrieverProvider"); + public String getAgentImplementationVersion() { + try (JarFile agentJar = new JarFile(agentPath)) { + return agentJar + .getManifest() + .getMainAttributes() + .getValue(Attributes.Name.IMPLEMENTATION_VERSION); + } catch (IOException e) { + throw new IllegalStateException(e); } + } - SmokeTestRunner smokeTestRunner = (SmokeTestRunner) getTestRunner(); - smokeTestRunner.setTelemetryRetriever( - ((TelemetryRetrieverProvider) testInstance).getTelemetryRetriever()); + public SmokeTestOutput start(int jdk) { + return start(String.valueOf(jdk), null, false); + } - super.beforeEach(extensionContext); + public SmokeTestOutput start(String jdk, String serverVersion, boolean windows) { + autoCleanup.deferCleanup(() -> containerManager.stopTarget()); + + return new SmokeTestOutput( + this, + containerManager.startTarget( + getTargetImage.getTargetImage(jdk, serverVersion, windows), + agentPath, + jvmArgsEnvVarName, + extraEnv, + setServiceName, + extraResources, + extraPorts, + waitStrategy, + command)); + } + + @Override + public TelemetryRetriever getTelemetryRetriever() { + return telemetryRetriever; + } + + public static Builder builder(Function getTargetImage) { + return builder((jdk, serverVersion, windows) -> getTargetImage.apply(jdk)); + } + + public static Builder builder(GetTargetImage getTargetImage) { + return new Builder(getTargetImage); + } + + public static Builder springBoot(String imageTag) { + return builder( + jdk -> + String.format( + "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk%s-%s", + jdk, imageTag)) + .waitStrategy( + new TargetWaitStrategy.Log( + Duration.ofMinutes(1), ".*Started SpringbootApplication in.*")); + } + + private static TestContainerManager createContainerManager() { + return TestContainerManager.useWindowsContainers() + ? new WindowsTestContainerManager() + : new LinuxTestContainerManager(); + } + + public static class Builder { + private final GetTargetImage getTargetImage; + private String[] command; + private String jvmArgsEnvVarName = "JAVA_TOOL_OPTIONS"; + private boolean setServiceName = true; + private final Map extraEnv = new HashMap<>(); + private List extraResources = List.of(); + private TargetWaitStrategy waitStrategy; + private List extraPorts = List.of(); + private Duration telemetryTimeout = Duration.ofSeconds(30); + + private Builder(GetTargetImage getTargetImage) { + this.getTargetImage = getTargetImage; + } + + /** Sets the command to run in the target container. */ + @CanIgnoreReturnValue + public Builder command(String... command) { + this.command = command; + return this; + } + + /** Sets the environment variable name used to pass JVM arguments to the target application. */ + @CanIgnoreReturnValue + public Builder jvmArgsEnvVarName(String jvmArgsEnvVarName) { + this.jvmArgsEnvVarName = jvmArgsEnvVarName; + return this; + } + + /** Enables or disables setting the default service name for the target application. */ + @CanIgnoreReturnValue + public Builder setServiceName(boolean setServiceName) { + this.setServiceName = setServiceName; + return this; + } + + /** Adds an environment variable to the target application's environment. */ + @CanIgnoreReturnValue + public Builder env(String key, String value) { + this.extraEnv.put(key, value); + return this; + } + + /** Specifies additional files to copy to the target container. */ + @CanIgnoreReturnValue + public Builder extraResources(ResourceMapping... resources) { + this.extraResources = List.of(resources); + return this; + } + + /** Sets the wait strategy for the target container startup. */ + @CanIgnoreReturnValue + public Builder waitStrategy(@Nullable TargetWaitStrategy waitStrategy) { + this.waitStrategy = waitStrategy; + return this; + } + + /** Specifies additional ports to expose from the target container. */ + @CanIgnoreReturnValue + public Builder extraPorts(Integer... ports) { + this.extraPorts = List.of(ports); + return this; + } + + /** Sets the timeout duration for retrieving telemetry data. */ + @CanIgnoreReturnValue + public Builder telemetryTimeout(Duration telemetryTimeout) { + this.telemetryTimeout = telemetryTimeout; + return this; + } + + public SmokeTestInstrumentationExtension build() { + return new SmokeTestInstrumentationExtension( + getTargetImage, + command, + jvmArgsEnvVarName, + setServiceName, + extraEnv, + extraResources, + waitStrategy, + extraPorts, + telemetryTimeout); + } } } diff --git a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestOutput.java b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestOutput.java new file mode 100644 index 000000000000..33947f5d780d --- /dev/null +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestOutput.java @@ -0,0 +1,50 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.smoketest; + +import static java.util.stream.Collectors.toSet; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Set; +import java.util.function.Consumer; +import java.util.regex.Pattern; +import java.util.stream.Stream; +import org.testcontainers.containers.output.OutputFrame; +import org.testcontainers.containers.output.ToStringConsumer; + +public class SmokeTestOutput { + + private static final Pattern TRACE_ID_PATTERN = + Pattern.compile(".*trace_id=(?[a-zA-Z0-9]+).*"); + private final SmokeTestInstrumentationExtension extension; + private final Consumer output; + + public SmokeTestOutput( + SmokeTestInstrumentationExtension extension, Consumer output) { + this.extension = extension; + this.output = output; + } + + public static Stream findTraceId(String log) { + var m = TRACE_ID_PATTERN.matcher(log); + return m.matches() ? Stream.of(m.group("traceId")) : Stream.empty(); + } + + public void assertAgentVersionLogged() { + String version = extension.getAgentImplementationVersion(); + assertThat( + logLines().anyMatch(l -> l.contains("opentelemetry-javaagent - version: " + version))) + .isTrue(); + } + + public Set getLoggedTraceIds() { + return logLines().flatMap(SmokeTestOutput::findTraceId).collect(toSet()); + } + + public Stream logLines() { + return ((ToStringConsumer) output).toUtf8String().lines(); + } +} 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 935866770cba..1c54a42264dd 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/SmokeTestRunner.java @@ -18,15 +18,9 @@ */ public class SmokeTestRunner extends InstrumentationTestRunner { - private static final SmokeTestRunner INSTANCE = new SmokeTestRunner(); - private TelemetryRetriever telemetryRetriever; - public static SmokeTestRunner instance() { - return INSTANCE; - } - - private SmokeTestRunner() { + SmokeTestRunner() { super(OpenTelemetry.noop()); } 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 32ad80ca2763..aff06b8817b1 100644 --- a/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java +++ b/smoke-tests/src/main/java/io/opentelemetry/smoketest/TelemetryRetriever.java @@ -18,6 +18,7 @@ import io.opentelemetry.testing.internal.protobuf.GeneratedMessage; import io.opentelemetry.testing.internal.protobuf.InvalidProtocolBufferException; import io.opentelemetry.testing.internal.protobuf.util.JsonFormat; +import java.time.Duration; import java.util.Collection; import java.util.List; import java.util.concurrent.TimeUnit; @@ -28,9 +29,11 @@ public class TelemetryRetriever { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private final WebClient client; + private final Duration telemetryTimeout; - public TelemetryRetriever(int backendPort) { + public TelemetryRetriever(int backendPort, Duration telemetryTimeout) { client = WebClient.of("http://localhost:" + backendPort); + this.telemetryTimeout = telemetryTimeout; } public void clearTelemetry() { @@ -91,7 +94,7 @@ Collection waitForTelemetry(String path, Supplier builderConstructor) { @SuppressWarnings("SystemOut") private String waitForContent(String path) throws InterruptedException { long previousSize = 0; - long deadline = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(30); + long deadline = System.currentTimeMillis() + telemetryTimeout.toMillis(); String content = "[]"; while (System.currentTimeMillis() < deadline) { content = client.get(path).aggregate().join().contentUtf8(); 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 3e77810bfb1e..811352fe0f0c 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/AgentDebugLoggingTest.java @@ -9,25 +9,23 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") -class AgentDebugLoggingTest extends JavaSmokeTest { - @Override - protected String getTargetImage(String jdk) { - return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" - + jdk - + "-20250915.17728045097"; - } +class AgentDebugLoggingTest { - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log( - Duration.ofMinutes(1), ".*DEBUG io.opentelemetry.javaagent.tooling.VersionLogger.*"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20250915.17728045097") + .waitStrategy( + new TargetWaitStrategy.Log( + Duration.ofMinutes(1), + ".*DEBUG io.opentelemetry.javaagent.tooling.VersionLogger.*")) + .build(); @DisplayName("verifies that debug logging is working by checking for a debug log on startup") @Test void verifyLogging() { - startTarget(8); + testing.start(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 608ab18d2763..280539fe5edb 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/DeclarativeConfigurationSmokeTest.java @@ -12,44 +12,27 @@ import io.opentelemetry.semconv.incubating.HostIncubatingAttributes; import io.opentelemetry.semconv.incubating.ProcessIncubatingAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; -import java.time.Duration; -import java.util.List; -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 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")); - } +class DeclarativeConfigurationSmokeTest { - @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.*"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20241021.11448062567") + .env("OTEL_EXPERIMENTAL_CONFIG_FILE", "declarative-config.yaml") + .extraResources(ResourceMapping.of("declarative-config.yaml", "/declarative-config.yaml")) + .build(); @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void springBootSmokeTest(int jdk) { - startTarget(jdk); + testing.start(jdk); - client().get("/greeting").aggregate().join(); + testing.client().get("/greeting").aggregate().join(); // There is one span (io.opentelemetry.opentelemetry-instrumentation-annotations-1.16 is // not used, because instrumentation_mode=none) diff --git a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java b/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java deleted file mode 100644 index 88ebff9a2e72..000000000000 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/JavaSmokeTest.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -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 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; - -public abstract class JavaSmokeTest implements TelemetryRetrieverProvider { - - @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(); - private static TelemetryRetriever 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)); - } - - /** Subclasses can override this method to pass jvm arguments in another environment variable */ - protected String getJvmArgsEnvVarName() { - return "JAVA_TOOL_OPTIONS"; - } - - /** Subclasses can override this method to customise target application's environment */ - protected Map getExtraEnv() { - return emptyMap(); - } - - /** Subclasses can override this method to disable setting default service name */ - protected boolean getSetServiceName() { - return true; - } - - /** Subclasses can override this method to provide additional files to copy to target container */ - protected List getExtraResources() { - return emptyList(); - } - - /** - * Subclasses can override this method to provide additional ports that should be exposed from the - * target container - */ - protected List getExtraPorts() { - return emptyList(); - } - - @BeforeAll - static void setUp() { - containerManager.startEnvironmentOnce(); - telemetryRetriever = new TelemetryRetriever(containerManager.getBackendMappedPort()); - } - - 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(() -> containerManager.stopTarget()); - - return containerManager.startTarget( - targetImage, - agentPath, - getJvmArgsEnvVarName(), - getExtraEnv(), - getSetServiceName(), - getExtraResources(), - getExtraPorts(), - getWaitStrategy(), - getCommand()); - } - - protected abstract String getTargetImage(String jdk); - - protected String getTargetImage(String jdk, String serverVersion, boolean windows) { - return getTargetImage(jdk); - } - - protected TargetWaitStrategy getWaitStrategy() { - return null; - } - - protected String[] getCommand() { - return null; - } - - 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) { - return ((ToStringConsumer) output).toUtf8String().lines(); - } - - protected static Set getLoggedTraceIds(Consumer output) { - return logLines(output).flatMap(JavaSmokeTest::findTraceId).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() - : new LinuxTestContainerManager(); - } - - @Override - public TelemetryRetriever getTelemetryRetriever() { - return telemetryRetriever; - } -} 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 57233a9a8d0c..2e57c8c77cd7 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/LogsSmokeTest.java @@ -8,32 +8,24 @@ import static org.assertj.core.api.Assertions.assertThat; import io.opentelemetry.sdk.logs.data.LogRecordData; -import java.time.Duration; import java.util.Collection; 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 LogsSmokeTest extends JavaSmokeTest { - @Override - protected String getTargetImage(String jdk) { - return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" - + jdk - + "-20211213.1570880324"; - } +class LogsSmokeTest { - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log( - Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20211213.1570880324").build(); @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void shouldExportLogs(int jdk) { - startTarget(jdk); - client().get("/greeting").aggregate().join(); + testing.start(jdk); + testing.client().get("/greeting").aggregate().join(); 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 9f7d3ea00946..d2d0e44cc0d5 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/QuarkusSmokeTest.java @@ -8,45 +8,31 @@ import io.opentelemetry.semconv.ServiceAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; import java.time.Duration; -import java.util.jar.Attributes; -import java.util.jar.JarFile; 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 QuarkusSmokeTest extends JavaSmokeTest { - @Override - protected String getTargetImage(String jdk) { - return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-quarkus:jdk" - + jdk - + "-20250915.17728045126"; - } - - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Listening on.*"); - } - - @Override - protected boolean getSetServiceName() { - return false; - } +class QuarkusSmokeTest { + + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.builder( + jdk -> + "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-quarkus:jdk" + + jdk + + "-20250915.17728045126") + .waitStrategy(new TargetWaitStrategy.Log(Duration.ofMinutes(1), ".*Listening on.*")) + .setServiceName(false) + .build(); @ParameterizedTest @ValueSource(ints = {17, 21, 23}) // Quarkus 3.7+ requires Java 17+ void quarkusSmokeTest(int jdk) throws Exception { - startTarget(jdk); - String currentAgentVersion; - try (JarFile agentJar = new JarFile(agentPath)) { - currentAgentVersion = - agentJar - .getManifest() - .getMainAttributes() - .getValue(Attributes.Name.IMPLEMENTATION_VERSION); - } + testing.start(jdk); - client().get("/hello").aggregate().join(); + testing.client().get("/hello").aggregate().join(); testing.waitAndAssertTraces( trace -> @@ -58,7 +44,7 @@ void quarkusSmokeTest(int jdk) throws Exception { resource .hasAttribute( TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, - currentAgentVersion) + testing.getAgentImplementationVersion()) .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 41b66d60f333..1509d7ff21af 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SdkDisabledSmokeTest.java @@ -7,43 +7,29 @@ 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 java.time.Duration; 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; -import org.testcontainers.containers.output.OutputFrame; @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"; - } +class SdkDisabledSmokeTest { - @Override - protected Map getExtraEnv() { - return Map.of("OTEL_SDK_DISABLED", "true"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20211213.1570880324") + .env("OTEL_SDK_DISABLED", "true") + .telemetryTimeout(Duration.ofSeconds(5)) + .build(); @ParameterizedTest @ValueSource(ints = {8, 11, 17}) void noopSdkSmokeTest(int jdk) throws Exception { - Consumer output = startTarget(jdk); - String currentAgentVersion = - new JarFile(agentPath) - .getManifest() - .getMainAttributes() - .get(Attributes.Name.IMPLEMENTATION_VERSION) - .toString(); - - assertThat(client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); + SmokeTestOutput output = testing.start(jdk); + assertThat(testing.client().get("/greeting").aggregate().join().contentUtf8()).isEqualTo("Hi!"); assertThat(testing.spans()).isEmpty(); - assertVersionLogged(output, currentAgentVersion); + output.assertAgentVersionLogged(); 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 1b9a0070775b..b377a363ee13 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SecurityManagerSmokeTest.java @@ -5,32 +5,28 @@ package io.opentelemetry.smoketest; -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 { +class SecurityManagerSmokeTest { - @Override - protected String getTargetImage(String jdk) { - return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-security-manager:jdk" - + jdk - + "-20250915.17728045123"; - } - - @Override - protected Map getExtraEnv() { - return Collections.singletonMap( - "OTEL_JAVAAGENT_EXPERIMENTAL_SECURITY_MANAGER_SUPPORT_ENABLED", "true"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.builder( + jdk -> + "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-security-manager:jdk" + + jdk + + "-20250915.17728045123") + .env("OTEL_JAVAAGENT_EXPERIMENTAL_SECURITY_MANAGER_SUPPORT_ENABLED", "true") + .build(); @ParameterizedTest @ValueSource(ints = {8, 11, 17, 21, 23}) void securityManagerSmokeTest(int jdk) { - startTarget(jdk); + testing.start(jdk); testing.waitAndAssertTraces( 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 index 0029c10d0765..e2ccfe8f455f 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/SpringBootSmokeTest.java @@ -14,58 +14,31 @@ import io.opentelemetry.semconv.incubating.OsIncubatingAttributes; import io.opentelemetry.semconv.incubating.TelemetryIncubatingAttributes; import io.opentelemetry.semconv.incubating.ThreadIncubatingAttributes; -import java.time.Duration; 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.api.extension.RegisterExtension; 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 { - @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; - } +class SpringBootSmokeTest { - @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.*"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20241021.11448062567") + .setServiceName(false) + .env("OTEL_METRICS_EXPORTER", "otlp") + .env("OTEL_RESOURCE_ATTRIBUTES", "foo=bar") + .build(); @ParameterizedTest @ValueSource(ints = {8, 11, 17, 21, 23}) - void springBootSmokeTest(int jdk) throws Exception { - Consumer output = startTarget(jdk); - String currentAgentVersion; - try (JarFile agentJar = new JarFile(agentPath)) { - currentAgentVersion = - agentJar - .getManifest() - .getMainAttributes() - .getValue(Attributes.Name.IMPLEMENTATION_VERSION); - } + void springBootSmokeTest(int jdk) { + SmokeTestOutput output = testing.start(jdk); - var response = client().get("/greeting").aggregate().join(); + var response = testing.client().get("/greeting").aggregate().join(); assertThat(response.contentUtf8()).isEqualTo("Hi!"); testing.waitAndAssertTraces( @@ -82,7 +55,7 @@ void springBootSmokeTest(int jdk) throws Exception { resource .hasAttribute( TelemetryIncubatingAttributes.TELEMETRY_DISTRO_VERSION, - currentAgentVersion) + testing.getAgentImplementationVersion()) .hasAttribute( satisfies( OsIncubatingAttributes.OS_TYPE, a -> a.isNotNull())) @@ -95,10 +68,10 @@ void springBootSmokeTest(int jdk) throws Exception { span -> span.hasName("WebController.withSpan"))); // Check agent version is logged on startup - assertVersionLogged(output, currentAgentVersion); + output.assertAgentVersionLogged(); // Check trace IDs are logged via MDC instrumentation - Set loggedTraceIds = getLoggedTraceIds(output); + Set loggedTraceIds = output.getLoggedTraceIds(); List spans = testing.spans(); Set spanTraceIds = spans.stream().map(SpanData::getTraceId).collect(Collectors.toSet()); assertThat(loggedTraceIds).isEqualTo(spanTraceIds); 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 index db814482335c..af6c87e613f6 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3MultiPropagationTest.java @@ -5,13 +5,18 @@ package io.opentelemetry.smoketest.propagation; -import java.util.Map; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class B3MultiPropagationTest extends PropagationTest { + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + builder().env("otel.propagators", "b3multi").build(); + @Override - protected Map getExtraEnv() { - return Map.of("otel.propagators", "b3multi"); + protected SmokeTestInstrumentationExtension testing() { + return testing; } } 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 index 73fc15912935..3126c5bef5de 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/B3PropagationTest.java @@ -5,13 +5,18 @@ package io.opentelemetry.smoketest.propagation; -import java.util.Map; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class B3PropagationTest extends PropagationTest { + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + builder().env("otel.propagators", "b3").build(); + @Override - protected Map getExtraEnv() { - return Map.of("otel.propagators", "b3"); + protected SmokeTestInstrumentationExtension testing() { + return testing; } } 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 index a765f0a43006..3671bb04f143 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/DefaultPropagationTest.java @@ -5,7 +5,16 @@ package io.opentelemetry.smoketest.propagation; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") -class DefaultPropagationTest extends PropagationTest {} +class DefaultPropagationTest extends PropagationTest { + @RegisterExtension static final SmokeTestInstrumentationExtension testing = builder().build(); + + @Override + protected SmokeTestInstrumentationExtension testing() { + return testing; + } +} 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 698f5980b0a6..0c69e3654cac 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,40 +7,27 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.smoketest.JavaSmokeTest; -import io.opentelemetry.smoketest.TargetWaitStrategy; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; -import java.time.Duration; -import java.util.Map; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @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"; - } +class OtTracePropagationTest { - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log( - Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); - } + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + SmokeTestInstrumentationExtension.springBoot("20211213.1570880324") + .env("otel.propagators", "ottrace") + .build(); @Test public void shouldPropagate() { - startTarget(11); - AggregatedHttpResponse response = client().get("/front").aggregate().join(); + testing.start(11); + AggregatedHttpResponse response = testing.client().get("/front").aggregate().join(); var traceId = testing.waitForTraces(1).get(0).get(0).getTraceId().substring(16); 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 index ab4ef67aa6e9..ad0a27915425 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 @@ -7,33 +7,24 @@ import static org.assertj.core.api.Assertions.assertThat; -import io.opentelemetry.smoketest.JavaSmokeTest; -import io.opentelemetry.smoketest.TargetWaitStrategy; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import io.opentelemetry.testing.internal.armeria.common.AggregatedHttpResponse; -import java.time.Duration; import org.junit.jupiter.api.Test; -public abstract class PropagationTest extends JavaSmokeTest { +public abstract class PropagationTest { - @Override - protected String getTargetImage(String jdk) { - return "ghcr.io/open-telemetry/opentelemetry-java-instrumentation/smoke-test-spring-boot:jdk" - + jdk - + "-20211213.1570880324"; + protected static SmokeTestInstrumentationExtension.Builder builder() { + return SmokeTestInstrumentationExtension.springBoot("20211213.1570880324"); } - @Override - protected TargetWaitStrategy getWaitStrategy() { - return new TargetWaitStrategy.Log( - Duration.ofMinutes(1), ".*Started SpringbootApplication in.*"); - } + protected abstract SmokeTestInstrumentationExtension testing(); @Test public void shouldPropagate() { - startTarget(11); - AggregatedHttpResponse response = client().get("/front").aggregate().join(); + testing().start(11); + AggregatedHttpResponse response = testing().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()).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 index 5bb4b70da593..1ba85b912e7c 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/W3CPropagationTest.java @@ -5,13 +5,18 @@ package io.opentelemetry.smoketest.propagation; -import java.util.Map; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class W3CPropagationTest extends PropagationTest { + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + builder().env("otel.propagators", "tracecontext").build(); + @Override - protected Map getExtraEnv() { - return Map.of("otel.propagators", "tracecontext"); + protected SmokeTestInstrumentationExtension testing() { + return testing; } } 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 index 71d2968457d5..55f255861d85 100644 --- a/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java +++ b/smoke-tests/src/test/java/io/opentelemetry/smoketest/propagation/XRayPropagationTest.java @@ -5,13 +5,18 @@ package io.opentelemetry.smoketest.propagation; -import java.util.Map; +import io.opentelemetry.smoketest.SmokeTestInstrumentationExtension; import org.junit.jupiter.api.condition.DisabledIf; +import org.junit.jupiter.api.extension.RegisterExtension; @DisabledIf("io.opentelemetry.smoketest.TestContainerManager#useWindowsContainers") class XRayPropagationTest extends PropagationTest { + @RegisterExtension + static final SmokeTestInstrumentationExtension testing = + builder().env("otel.propagators", "xray").build(); + @Override - protected Map getExtraEnv() { - return Map.of("otel.propagators", "xray"); + protected SmokeTestInstrumentationExtension testing() { + return testing; } }