Add a junit4 rule for OTel testing. (#1996)

* Add a junit4 rule for OTel testing.

* Docs to 4

* A bit more 4

* Volatile just in case
This commit is contained in:
Anuraag Agrawal 2020-11-05 11:37:51 +09:00 committed by GitHub
parent d0e0b5a553
commit f01456bebd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 239 additions and 2 deletions

View File

@ -9,7 +9,9 @@ ext.moduleName = 'io.opentelemetry.sdk.testing'
dependencies {
api project(':opentelemetry-api')
api project(':opentelemetry-sdk')
api libraries.junit_jupiter_api
compileOnly libraries.junit
compileOnly libraries.junit_jupiter_api
annotationProcessor libraries.auto_value
}

View File

@ -0,0 +1,112 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.junit4;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.propagation.HttpTraceContext;
import io.opentelemetry.context.propagation.DefaultContextPropagators;
import io.opentelemetry.exporter.inmemory.InMemorySpanExporter;
import io.opentelemetry.sdk.OpenTelemetrySdk;
import io.opentelemetry.sdk.trace.TracerSdkManagement;
import io.opentelemetry.sdk.trace.TracerSdkProvider;
import io.opentelemetry.sdk.trace.data.SpanData;
import io.opentelemetry.sdk.trace.export.SimpleSpanProcessor;
import java.util.List;
import org.junit.rules.ExternalResource;
/**
* A JUnit4 rule which sets up the {@link OpenTelemetrySdk} for testing, resetting state between
* tests. This rule cannot be used with {@link org.junit.ClassRule}.
*
* <pre>{@code
* > public class CoolTest {
* > {@literal @}Rule
* > public OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create();
* >
* > private Tracer tracer;
* >
* > {@literal @}Before
* > public void setUp() {
* > tracer = otelTesting.getOpenTelemetry().getTracer("test");
* > }
* >
* > {@literal @}Test
* > public void test() {
* > tracer.spanBuilder("name").startSpan().end();
* > assertThat(otelTesting.getSpans()).containsExactly(expected);
* > }
* > }
* }</pre>
*/
public class OpenTelemetryRule extends ExternalResource {
/**
* Returns a {@link OpenTelemetryRule} with a default SDK initialized with an in-memory span
* exporter and W3C trace context propagation.
*/
public static OpenTelemetryRule create() {
InMemorySpanExporter spanExporter = InMemorySpanExporter.create();
TracerSdkProvider tracerProvider = TracerSdkProvider.builder().build();
tracerProvider.addSpanProcessor(SimpleSpanProcessor.builder(spanExporter).build());
OpenTelemetrySdk openTelemetry =
OpenTelemetrySdk.builder()
.setPropagators(
DefaultContextPropagators.builder()
.addTextMapPropagator(HttpTraceContext.getInstance())
.build())
.setTracerProvider(tracerProvider)
.build();
return new OpenTelemetryRule(openTelemetry, spanExporter);
}
private final OpenTelemetrySdk openTelemetry;
private final InMemorySpanExporter spanExporter;
private volatile OpenTelemetry previousGlobalOpenTelemetry;
private OpenTelemetryRule(OpenTelemetrySdk openTelemetry, InMemorySpanExporter spanExporter) {
this.openTelemetry = openTelemetry;
this.spanExporter = spanExporter;
}
/** Returns the {@link OpenTelemetrySdk} created by this extension. */
public OpenTelemetry getOpenTelemetry() {
return openTelemetry;
}
/** Returns the {@link TracerSdkManagement} created by this extension. */
public TracerSdkManagement getTracerManagement() {
return openTelemetry.getTracerManagement();
}
/** Returns all the exported {@link SpanData} so far. */
public List<SpanData> getSpans() {
return 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();
}
@Override
protected void before() throws Throwable {
previousGlobalOpenTelemetry = OpenTelemetry.get();
OpenTelemetry.set(openTelemetry);
clearSpans();
}
@Override
protected void after() {
OpenTelemetry.set(previousGlobalOpenTelemetry);
}
}

View File

@ -67,7 +67,7 @@ public class OpenTelemetryExtension
private final OpenTelemetrySdk openTelemetry;
private final InMemorySpanExporter spanExporter;
private OpenTelemetry previousGlobalOpenTelemetry;
private volatile OpenTelemetry previousGlobalOpenTelemetry;
private OpenTelemetryExtension(
OpenTelemetrySdk openTelemetry, InMemorySpanExporter spanExporter) {

View File

@ -0,0 +1,64 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.junit4;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
public class OpenTelemetryRuleTest {
@Rule public OpenTelemetryRule otelTesting = OpenTelemetryRule.create();
private static OpenTelemetry openTelemetryBeforeTest;
// Class callbacks happen outside the rule so we can verify the restoration behavior in them.
@BeforeClass
public static void beforeTest() {
openTelemetryBeforeTest = OpenTelemetry.get();
}
@AfterClass
public static void afterTest() {
assertThat(OpenTelemetry.get()).isSameAs(openTelemetryBeforeTest);
}
private Tracer tracer;
@Before
public void setup() {
tracer = otelTesting.getOpenTelemetry().getTracer("test");
}
@Test
public void exportSpan() {
tracer.spanBuilder("test").startSpan().end();
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
// Spans cleared between tests, not when retrieving
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
}
// We have two tests to verify spans get cleared up between tests.
@Test
public void exportSpanAgain() {
tracer.spanBuilder("test").startSpan().end();
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
// Spans cleared between tests, not when retrieving
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.sdk.testing.junit5;
import static org.assertj.core.api.Assertions.assertThat;
import io.opentelemetry.api.OpenTelemetry;
import io.opentelemetry.api.trace.Tracer;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
class OpenTelemetryExtensionTest {
@RegisterExtension
static final OpenTelemetryExtension otelTesting = OpenTelemetryExtension.create();
private static OpenTelemetry openTelemetryBeforeTest;
// Class callbacks happen outside the rule so we can verify the restoration behavior in them.
@BeforeAll
public static void beforeTest() {
openTelemetryBeforeTest = OpenTelemetry.get();
}
@AfterAll
public static void afterTest() {
assertThat(OpenTelemetry.get()).isSameAs(openTelemetryBeforeTest);
}
private final Tracer tracer = otelTesting.getOpenTelemetry().getTracer("test");
@Test
public void exportSpan() {
tracer.spanBuilder("test").startSpan().end();
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
// Spans cleared between tests, not when retrieving
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
}
// We have two tests to verify spans get cleared up between tests.
@Test
public void exportSpanAgain() {
tracer.spanBuilder("test").startSpan().end();
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
// Spans cleared between tests, not when retrieving
assertThat(otelTesting.getSpans())
.hasOnlyOneElementSatisfying(span -> assertThat(span.getName()).isEqualTo("test"));
}
}