From 94b7af473be09f2b826d3501fc196bf1e819f9c9 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 4 Jun 2024 08:57:41 +0200 Subject: [PATCH 1/4] test helper for auto configure --- sdk/testing/build.gradle.kts | 2 + .../sdk/testing/junit4/OpenTelemetryRule.java | 50 ++----- .../junit5/OpenTelemetryExtension.java | 132 +----------------- .../AutoConfiguredOpenTelemetryTesting.java | 71 ++++++++++ .../testing/sdk/InMemoryComponentLoader.java | 93 ++++++++++++ .../sdk/testing/sdk/OpenTelemetryTestSdk.java | 87 ++++++++++++ .../sdk/testing/sdk/OpenTelemetryTesting.java | 100 +++++++++++++ 7 files changed, 371 insertions(+), 164 deletions(-) create mode 100644 sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java create mode 100644 sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/InMemoryComponentLoader.java create mode 100644 sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTestSdk.java create mode 100644 sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTesting.java diff --git a/sdk/testing/build.gradle.kts b/sdk/testing/build.gradle.kts index a9f2534aafd..6e601294b63 100644 --- a/sdk/testing/build.gradle.kts +++ b/sdk/testing/build.gradle.kts @@ -13,6 +13,8 @@ dependencies { compileOnly("org.assertj:assertj-core") compileOnly("junit:junit") compileOnly("org.junit.jupiter:junit-jupiter-api") + compileOnly(project(":sdk-extensions:autoconfigure")) + compileOnly("org.awaitility:awaitility") annotationProcessor("com.google.auto.value:auto-value") diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java index 7cf3a873cba..bf47718f5ac 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit4/OpenTelemetryRule.java @@ -7,24 +7,19 @@ import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.logs.SdkLoggerProvider; import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; import io.opentelemetry.sdk.metrics.data.AggregationTemporality; import io.opentelemetry.sdk.metrics.data.MetricData; import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; -import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk; import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.function.Supplier; import org.junit.rules.ExternalResource; /** @@ -63,45 +58,24 @@ public final class OpenTelemetryRule extends ExternalResource { * exporter and W3C trace context propagation. */ public static OpenTelemetryRule create() { - InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + OpenTelemetryTestSdk testSdk = OpenTelemetryTestSdk.create(); - SdkTracerProvider tracerProvider = - SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build(); - - InMemoryMetricReader metricReader = InMemoryMetricReader.create(); - - SdkMeterProvider meterProvider = - SdkMeterProvider.builder().registerMetricReader(metricReader).build(); - - InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); - - SdkLoggerProvider loggerProvider = - SdkLoggerProvider.builder() - .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .build(); - - OpenTelemetrySdk openTelemetry = - OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(tracerProvider) - .setMeterProvider(meterProvider) - .setLoggerProvider(loggerProvider) - .build(); - - return new OpenTelemetryRule(openTelemetry, spanExporter, metricReader, logRecordExporter); + return new OpenTelemetryRule( + testSdk.getOpenTelemetry(), + testSdk.getSpanExporter(), + testSdk.getMetricReader(), + testSdk.getLogRecordExporter()); } private final OpenTelemetrySdk openTelemetry; private final InMemorySpanExporter spanExporter; - private final InMemoryMetricReader metricReader; + private final Supplier> metricReader; private final InMemoryLogRecordExporter logRecordExporter; private OpenTelemetryRule( OpenTelemetrySdk openTelemetry, InMemorySpanExporter spanExporter, - InMemoryMetricReader metricReader, + Supplier> metricReader, InMemoryLogRecordExporter logRecordExporter) { this.openTelemetry = openTelemetry; this.spanExporter = spanExporter; @@ -125,7 +99,7 @@ public List getSpans() { * @since 1.15.0 */ public List getMetrics() { - return new ArrayList<>(metricReader.collectAllMetrics()); + return new ArrayList<>(metricReader.get()); } /** diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java index 3aedad968c7..2ed58c00b4b 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/junit5/OpenTelemetryExtension.java @@ -5,29 +5,10 @@ package io.opentelemetry.sdk.testing.junit5; -import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; - import io.opentelemetry.api.GlobalOpenTelemetry; -import io.opentelemetry.api.OpenTelemetry; -import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; -import io.opentelemetry.context.propagation.ContextPropagators; import io.opentelemetry.sdk.OpenTelemetrySdk; -import io.opentelemetry.sdk.logs.SdkLoggerProvider; -import io.opentelemetry.sdk.logs.data.LogRecordData; -import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; -import io.opentelemetry.sdk.metrics.SdkMeterProvider; -import io.opentelemetry.sdk.metrics.data.AggregationTemporality; -import io.opentelemetry.sdk.metrics.data.MetricData; -import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; -import io.opentelemetry.sdk.testing.assertj.TracesAssert; -import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; -import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; -import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; -import io.opentelemetry.sdk.trace.SdkTracerProvider; -import io.opentelemetry.sdk.trace.data.SpanData; -import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; -import java.util.ArrayList; -import java.util.List; +import io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk; +import io.opentelemetry.sdk.testing.sdk.OpenTelemetryTesting; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.BeforeAllCallback; import org.junit.jupiter.api.extension.BeforeEachCallback; @@ -57,7 +38,7 @@ * // } * } */ -public final class OpenTelemetryExtension +public final class OpenTelemetryExtension extends OpenTelemetryTesting implements BeforeEachCallback, BeforeAllCallback, AfterAllCallback { /** @@ -65,113 +46,12 @@ public final class OpenTelemetryExtension * exporter and W3C trace context propagation. */ public static OpenTelemetryExtension create() { - InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); - - SdkTracerProvider tracerProvider = - SdkTracerProvider.builder() - .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) - .build(); - - InMemoryMetricReader metricReader = InMemoryMetricReader.create(); - - SdkMeterProvider meterProvider = - SdkMeterProvider.builder().registerMetricReader(metricReader).build(); - - InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); - - SdkLoggerProvider loggerProvider = - SdkLoggerProvider.builder() - .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) - .build(); - - OpenTelemetrySdk openTelemetry = - OpenTelemetrySdk.builder() - .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) - .setTracerProvider(tracerProvider) - .setMeterProvider(meterProvider) - .setLoggerProvider(loggerProvider) - .build(); - - return new OpenTelemetryExtension(openTelemetry, spanExporter, metricReader, logRecordExporter); - } - - private final OpenTelemetrySdk openTelemetry; - private final InMemorySpanExporter spanExporter; - private final InMemoryMetricReader metricReader; - private final InMemoryLogRecordExporter logRecordExporter; - - private OpenTelemetryExtension( - OpenTelemetrySdk openTelemetry, - InMemorySpanExporter spanExporter, - InMemoryMetricReader metricReader, - InMemoryLogRecordExporter logRecordExporter) { - this.openTelemetry = openTelemetry; - this.spanExporter = spanExporter; - this.metricReader = metricReader; - this.logRecordExporter = logRecordExporter; - } - - /** Returns the {@link OpenTelemetrySdk} created by this extension. */ - public OpenTelemetry getOpenTelemetry() { - return openTelemetry; - } - - /** Returns all the exported {@link SpanData} so far. */ - public List getSpans() { - return spanExporter.getFinishedSpanItems(); - } - - /** - * Returns the current {@link MetricData} in {@link AggregationTemporality#CUMULATIVE} format. - * - * @since 1.15.0 - */ - public List getMetrics() { - return new ArrayList<>(metricReader.collectAllMetrics()); - } - - /** - * Returns all the exported {@link LogRecordData} so far. - * - * @since 1.32.0 - */ - public List getLogRecords() { - return new ArrayList<>(logRecordExporter.getFinishedLogRecordItems()); - } - - /** - * Returns a {@link TracesAssert} for asserting on the currently exported traces. This method - * requires AssertJ to be on the classpath. - */ - public TracesAssert assertTraces() { - return assertThat(spanExporter.getFinishedSpanItems()); - } - /** - * Clears the collected exported {@link SpanData}. Consider making your test smaller instead of - * manually clearing state using this method. - */ - public void clearSpans() { - spanExporter.reset(); + return new OpenTelemetryExtension(OpenTelemetryTestSdk.create()); } - /** - * Clears all registered metric instruments, such that {@link #getMetrics()} is empty. - * - * @since 1.15.0 - */ - public void clearMetrics() { - SdkMeterProviderUtil.resetForTest(openTelemetry.getSdkMeterProvider()); - } - - /** - * Clears the collected exported {@link LogRecordData}. Consider making your test smaller instead - * of manually clearing state using this method. - * - * @since 1.32.0 - */ - public void clearLogRecords() { - logRecordExporter.reset(); + private OpenTelemetryExtension(OpenTelemetryTestSdk openTelemetryTestSdk) { + super(openTelemetryTestSdk); } @Override diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java new file mode 100644 index 00000000000..5f10141d31f --- /dev/null +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java @@ -0,0 +1,71 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.testing.sdk; + +import static org.awaitility.Awaitility.await; + +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk; +import io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdkBuilder; +import io.opentelemetry.sdk.autoconfigure.internal.AutoConfigureUtil; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.testing.assertj.TraceAssert; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import java.time.Duration; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Consumer; + +public class AutoConfiguredOpenTelemetryTesting extends OpenTelemetryTesting { + + static final String MEMORY_EXPORTER = "memory"; + + public static AutoConfiguredOpenTelemetryTesting create(Map properties) { + return new AutoConfiguredOpenTelemetryTesting(getOpenTelemetrySdk(properties)); + } + + public AutoConfiguredOpenTelemetryTesting(OpenTelemetryTestSdk sdk) { + super(sdk); + } + + private static OpenTelemetryTestSdk getOpenTelemetrySdk(Map properties) { + + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + InMemoryMetricExporter metricExporter = + InMemoryMetricExporter.create(AggregationTemporality.DELTA); + InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); + + AutoConfiguredOpenTelemetrySdkBuilder sdkBuilder = + AutoConfiguredOpenTelemetrySdk.builder() + .addPropertiesSupplier(AutoConfiguredOpenTelemetryTesting::getProperties) + .addPropertiesSupplier(() -> properties); + AutoConfigureUtil.setComponentLoader( + sdkBuilder, new InMemoryComponentLoader(spanExporter, metricExporter, logRecordExporter)); + OpenTelemetrySdk openTelemetrySdk = sdkBuilder.build().getOpenTelemetrySdk(); + return new OpenTelemetryTestSdk( + openTelemetrySdk, spanExporter, metricExporter::getFinishedMetricItems, logRecordExporter); + } + + private static Map getProperties() { + Map map = new HashMap<>(); + map.put("otel.bsp.schedule.delay", "10"); + map.put("otel.metric.export.interval", "10"); + map.put("otel.blrp.schedule.delay", "10"); + map.put("otel.traces.exporter", MEMORY_EXPORTER); + map.put("otel.metrics.exporter", MEMORY_EXPORTER); + map.put("otel.logs.exporter", MEMORY_EXPORTER); + return map; + } + + /** needs org.awaitility:awaitility to be on the classpath */ + public void assertTraces(Consumer... assertions) { + await() + .atMost(Duration.ofSeconds(1)) + .untilAsserted(() -> assertTraces().hasTracesSatisfyingExactly(assertions)); + } +} diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/InMemoryComponentLoader.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/InMemoryComponentLoader.java new file mode 100644 index 00000000000..bdadce402da --- /dev/null +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/InMemoryComponentLoader.java @@ -0,0 +1,93 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.testing.sdk; + +import io.opentelemetry.sdk.autoconfigure.internal.ComponentLoader; +import io.opentelemetry.sdk.autoconfigure.internal.SpiHelper; +import io.opentelemetry.sdk.autoconfigure.spi.ConfigProperties; +import io.opentelemetry.sdk.autoconfigure.spi.logs.ConfigurableLogRecordExporterProvider; +import io.opentelemetry.sdk.autoconfigure.spi.metrics.ConfigurableMetricExporterProvider; +import io.opentelemetry.sdk.autoconfigure.spi.traces.ConfigurableSpanExporterProvider; +import io.opentelemetry.sdk.metrics.export.MetricExporter; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricExporter; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.export.SpanExporter; +import java.util.Collections; +import java.util.List; + +class InMemoryComponentLoader implements ComponentLoader { + private final SpiHelper spiHelper = + SpiHelper.create(AutoConfiguredOpenTelemetryTesting.class.getClassLoader()); + private final InMemorySpanExporter spanExporter; + private final InMemoryMetricExporter metricExporter; + private final InMemoryLogRecordExporter logRecordExporter; + + public InMemoryComponentLoader( + InMemorySpanExporter spanExporter, + InMemoryMetricExporter metricExporter, + InMemoryLogRecordExporter logRecordExporter) { + this.spanExporter = spanExporter; + this.metricExporter = metricExporter; + this.logRecordExporter = logRecordExporter; + } + + @SuppressWarnings("unchecked") + @Override + public List load(Class spiClass) { + List list = spiHelper.load(spiClass); + if (spiClass == ConfigurableSpanExporterProvider.class) { + list.addAll( + (List) + Collections.singletonList( + new ConfigurableSpanExporterProvider() { + @Override + public SpanExporter createExporter(ConfigProperties configProperties) { + return spanExporter; + } + + @Override + public String getName() { + return AutoConfiguredOpenTelemetryTesting.MEMORY_EXPORTER; + } + })); + } + if (spiClass == ConfigurableMetricExporterProvider.class) { + list.addAll( + (List) + Collections.singletonList( + new ConfigurableMetricExporterProvider() { + @Override + public MetricExporter createExporter(ConfigProperties configProperties) { + return metricExporter; + } + + @Override + public String getName() { + return AutoConfiguredOpenTelemetryTesting.MEMORY_EXPORTER; + } + })); + } + if (spiClass == ConfigurableLogRecordExporterProvider.class) { + list.addAll( + (List) + Collections.singletonList( + new ConfigurableLogRecordExporterProvider() { + @Override + public InMemoryLogRecordExporter createExporter( + ConfigProperties configProperties) { + return logRecordExporter; + } + + @Override + public String getName() { + return AutoConfiguredOpenTelemetryTesting.MEMORY_EXPORTER; + } + })); + } + return list; + } +} diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTestSdk.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTestSdk.java new file mode 100644 index 00000000000..ad0c9f9246c --- /dev/null +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTestSdk.java @@ -0,0 +1,87 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.testing.sdk; + +import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator; +import io.opentelemetry.context.propagation.ContextPropagators; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.logs.SdkLoggerProvider; +import io.opentelemetry.sdk.logs.export.SimpleLogRecordProcessor; +import io.opentelemetry.sdk.metrics.SdkMeterProvider; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import io.opentelemetry.sdk.testing.exporter.InMemoryMetricReader; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.SdkTracerProvider; +import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor; +import java.util.Collection; +import java.util.function.Supplier; + +public class OpenTelemetryTestSdk { + private final OpenTelemetrySdk openTelemetry; + private final InMemorySpanExporter spanExporter; + private final Supplier> metricReader; + private final InMemoryLogRecordExporter logRecordExporter; + + OpenTelemetryTestSdk( + OpenTelemetrySdk openTelemetry, + InMemorySpanExporter spanExporter, + Supplier> metricReader, + InMemoryLogRecordExporter logRecordExporter) { + this.openTelemetry = openTelemetry; + this.spanExporter = spanExporter; + this.metricReader = metricReader; + this.logRecordExporter = logRecordExporter; + } + + public static OpenTelemetryTestSdk create() { + InMemorySpanExporter spanExporter = InMemorySpanExporter.create(); + + SdkTracerProvider tracerProvider = + SdkTracerProvider.builder() + .addSpanProcessor(SimpleSpanProcessor.create(spanExporter)) + .build(); + + InMemoryMetricReader metricReader = InMemoryMetricReader.create(); + + SdkMeterProvider meterProvider = + SdkMeterProvider.builder().registerMetricReader(metricReader).build(); + + InMemoryLogRecordExporter logRecordExporter = InMemoryLogRecordExporter.create(); + + SdkLoggerProvider loggerProvider = + SdkLoggerProvider.builder() + .addLogRecordProcessor(SimpleLogRecordProcessor.create(logRecordExporter)) + .build(); + + OpenTelemetrySdk openTelemetry = + OpenTelemetrySdk.builder() + .setPropagators(ContextPropagators.create(W3CTraceContextPropagator.getInstance())) + .setTracerProvider(tracerProvider) + .setMeterProvider(meterProvider) + .setLoggerProvider(loggerProvider) + .build(); + + return new OpenTelemetryTestSdk( + openTelemetry, spanExporter, metricReader::collectAllMetrics, logRecordExporter); + } + + public OpenTelemetrySdk getOpenTelemetry() { + return openTelemetry; + } + + public InMemorySpanExporter getSpanExporter() { + return spanExporter; + } + + public Supplier> getMetricReader() { + return metricReader; + } + + public InMemoryLogRecordExporter getLogRecordExporter() { + return logRecordExporter; + } +} diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTesting.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTesting.java new file mode 100644 index 00000000000..769f8060f21 --- /dev/null +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/OpenTelemetryTesting.java @@ -0,0 +1,100 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.testing.sdk; + +import static io.opentelemetry.sdk.testing.assertj.TracesAssert.assertThat; + +import io.opentelemetry.api.OpenTelemetry; +import io.opentelemetry.sdk.OpenTelemetrySdk; +import io.opentelemetry.sdk.logs.data.LogRecordData; +import io.opentelemetry.sdk.metrics.data.AggregationTemporality; +import io.opentelemetry.sdk.metrics.data.MetricData; +import io.opentelemetry.sdk.metrics.internal.SdkMeterProviderUtil; +import io.opentelemetry.sdk.testing.assertj.TracesAssert; +import io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter; +import io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter; +import io.opentelemetry.sdk.trace.data.SpanData; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.function.Supplier; + +public class OpenTelemetryTesting { + protected final OpenTelemetrySdk openTelemetry; + protected final InMemorySpanExporter spanExporter; + protected final Supplier> metricReader; + protected final InMemoryLogRecordExporter logRecordExporter; + + public OpenTelemetryTesting(OpenTelemetryTestSdk sdk) { + this.openTelemetry = sdk.getOpenTelemetry(); + this.spanExporter = sdk.getSpanExporter(); + this.metricReader = sdk.getMetricReader(); + this.logRecordExporter = sdk.getLogRecordExporter(); + } + + /** Returns the {@link OpenTelemetrySdk} created by this extension. */ + public OpenTelemetry getOpenTelemetry() { + return openTelemetry; + } + + /** Returns all the exported {@link SpanData} so far. */ + public List getSpans() { + return spanExporter.getFinishedSpanItems(); + } + + /** + * Returns the current {@link MetricData} in {@link AggregationTemporality#CUMULATIVE} format. + * + * @since 1.15.0 + */ + public List getMetrics() { + return new ArrayList<>(metricReader.get()); + } + + /** + * Returns all the exported {@link LogRecordData} so far. + * + * @since 1.32.0 + */ + public List getLogRecords() { + return new ArrayList<>(logRecordExporter.getFinishedLogRecordItems()); + } + + /** + * Returns a {@link TracesAssert} for asserting on the currently exported traces. This method + * requires AssertJ to be on the classpath. + */ + public TracesAssert assertTraces() { + return assertThat(spanExporter.getFinishedSpanItems()); + } + + /** + * Clears the collected exported {@link SpanData}. Consider making your test smaller instead of + * manually clearing state using this method. + */ + public void clearSpans() { + spanExporter.reset(); + } + + /** + * Clears all registered metric instruments, such that {@link #getMetrics()} is empty. + * + * @since 1.15.0 + */ + public void clearMetrics() { + SdkMeterProviderUtil.resetForTest(openTelemetry.getSdkMeterProvider()); + } + + /** + * Clears the collected exported {@link LogRecordData}. Consider making your test smaller instead + * of manually clearing state using this method. + * + * @since 1.32.0 + */ + public void clearLogRecords() { + logRecordExporter.reset(); + } +} From d1814ebbc61063a723108e640158272871691e9c Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Tue, 4 Jun 2024 09:04:34 +0200 Subject: [PATCH 2/4] test helper for auto configure --- .../sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java index 5f10141d31f..6871899ad87 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java @@ -63,7 +63,9 @@ private static Map getProperties() { } /** needs org.awaitility:awaitility to be on the classpath */ - public void assertTraces(Consumer... assertions) { + @SafeVarargs + @SuppressWarnings("varargs") + public final void assertTraces(Consumer... assertions) { await() .atMost(Duration.ofSeconds(1)) .untilAsserted(() -> assertTraces().hasTracesSatisfyingExactly(assertions)); From 606c931648eff10bc2cffa6127fbbfbef3e40d2b Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Fri, 7 Jun 2024 14:02:07 +0200 Subject: [PATCH 3/4] test helper for auto configure --- .../opentelemetry-sdk-testing.txt | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt index df26146497b..78c6220262f 100644 --- a/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt +++ b/docs/apidiffs/current_vs_latest/opentelemetry-sdk-testing.txt @@ -1,2 +1,39 @@ Comparing source compatibility of against -No changes. \ No newline at end of file +*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.testing.junit5.OpenTelemetryExtension (not serializable) + === CLASS FILE FORMAT VERSION: 52.0 <- 52.0 + *** MODIFIED SUPERCLASS: io.opentelemetry.sdk.testing.sdk.OpenTelemetryTesting (<- java.lang.Object) + --- REMOVED METHOD: PUBLIC(-) io.opentelemetry.sdk.testing.assertj.TracesAssert assertTraces() + --- REMOVED METHOD: PUBLIC(-) void clearLogRecords() + --- REMOVED METHOD: PUBLIC(-) void clearMetrics() + --- REMOVED METHOD: PUBLIC(-) void clearSpans() + --- REMOVED METHOD: PUBLIC(-) java.util.List getLogRecords() + --- REMOVED METHOD: PUBLIC(-) java.util.List getMetrics() + --- REMOVED METHOD: PUBLIC(-) io.opentelemetry.api.OpenTelemetry getOpenTelemetry() + --- REMOVED METHOD: PUBLIC(-) java.util.List getSpans() ++++ NEW CLASS: PUBLIC(+) io.opentelemetry.sdk.testing.sdk.AutoConfiguredOpenTelemetryTesting (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: io.opentelemetry.sdk.testing.sdk.OpenTelemetryTesting + +++ NEW CONSTRUCTOR: PUBLIC(+) AutoConfiguredOpenTelemetryTesting(io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk) + +++ NEW METHOD: PUBLIC(+) FINAL(+) void assertTraces(java.util.function.Consumer[]) + +++ NEW ANNOTATION: java.lang.SafeVarargs + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.testing.sdk.AutoConfiguredOpenTelemetryTesting create(java.util.Map) ++++ NEW CLASS: PUBLIC(+) io.opentelemetry.sdk.testing.sdk.OpenTelemetryTesting (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW CONSTRUCTOR: PUBLIC(+) OpenTelemetryTesting(io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk) + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.assertj.TracesAssert assertTraces() + +++ NEW METHOD: PUBLIC(+) void clearLogRecords() + +++ NEW METHOD: PUBLIC(+) void clearMetrics() + +++ NEW METHOD: PUBLIC(+) void clearSpans() + +++ NEW METHOD: PUBLIC(+) java.util.List getLogRecords() + +++ NEW METHOD: PUBLIC(+) java.util.List getMetrics() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.api.OpenTelemetry getOpenTelemetry() + +++ NEW METHOD: PUBLIC(+) java.util.List getSpans() ++++ NEW CLASS: PUBLIC(+) io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk (not serializable) + +++ CLASS FILE FORMAT VERSION: 52.0 <- n.a. + +++ NEW SUPERCLASS: java.lang.Object + +++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.testing.sdk.OpenTelemetryTestSdk create() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.exporter.InMemoryLogRecordExporter getLogRecordExporter() + +++ NEW METHOD: PUBLIC(+) java.util.function.Supplier> getMetricReader() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.OpenTelemetrySdk getOpenTelemetry() + +++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.testing.exporter.InMemorySpanExporter getSpanExporter() From 5782ca67ff017a9a01629c246d6737f74d57adf4 Mon Sep 17 00:00:00 2001 From: Gregor Zeitlinger Date: Mon, 10 Jun 2024 19:21:37 +0200 Subject: [PATCH 4/4] add test --- sdk/testing/build.gradle.kts | 1 + .../AutoConfiguredOpenTelemetryTesting.java | 2 +- ...utoConfiguredOpenTelemetryTestingTest.java | 35 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 sdk/testing/src/test/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTestingTest.java diff --git a/sdk/testing/build.gradle.kts b/sdk/testing/build.gradle.kts index 6e601294b63..e93d8a6ca27 100644 --- a/sdk/testing/build.gradle.kts +++ b/sdk/testing/build.gradle.kts @@ -20,4 +20,5 @@ dependencies { testImplementation("junit:junit") testImplementation("org.junit.vintage:junit-vintage-engine") + testImplementation(project(":sdk-extensions:autoconfigure")) } diff --git a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java index 6871899ad87..1d8064cc1bd 100644 --- a/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java +++ b/sdk/testing/src/main/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTesting.java @@ -29,7 +29,7 @@ public static AutoConfiguredOpenTelemetryTesting create(Map prop return new AutoConfiguredOpenTelemetryTesting(getOpenTelemetrySdk(properties)); } - public AutoConfiguredOpenTelemetryTesting(OpenTelemetryTestSdk sdk) { + private AutoConfiguredOpenTelemetryTesting(OpenTelemetryTestSdk sdk) { super(sdk); } diff --git a/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTestingTest.java b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTestingTest.java new file mode 100644 index 00000000000..a01969ec52b --- /dev/null +++ b/sdk/testing/src/test/java/io/opentelemetry/sdk/testing/sdk/AutoConfiguredOpenTelemetryTestingTest.java @@ -0,0 +1,35 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.sdk.testing.sdk; + +import io.opentelemetry.api.common.AttributeKey; +import java.util.Collections; +import org.junit.jupiter.api.Test; + +class AutoConfiguredOpenTelemetryTestingTest { + + @Test + void sdkEnabled() { + AutoConfiguredOpenTelemetryTesting testing = + AutoConfiguredOpenTelemetryTesting.create(Collections.emptyMap()); + testing.getOpenTelemetry().getTracer("test").spanBuilder("test").startSpan().end(); + testing.assertTraces(trace -> trace.hasSize(1)); + } + + @Test + void resourceAttributes() { + AutoConfiguredOpenTelemetryTesting testing = + AutoConfiguredOpenTelemetryTesting.create( + Collections.singletonMap("otel.resource.attributes", "foo=bar")); + testing.getOpenTelemetry().getTracer("test").spanBuilder("test").startSpan().end(); + testing.assertTraces( + trace -> + trace.hasSpansSatisfyingExactly( + span -> + span.hasResourceSatisfying( + resource -> resource.hasAttribute(AttributeKey.stringKey("foo"), "bar")))); + } +}