Run tests with javaagent. (#1643)

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
This commit is contained in:
Anuraag Agrawal 2021-01-05 06:13:24 +09:00 committed by GitHub
parent 5b2e4ce1c7
commit 8d74baa2e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
193 changed files with 2802 additions and 1861 deletions

20
.github/scripts/deadlock-detector.sh vendored Executable file
View File

@ -0,0 +1,20 @@
#!/bin/bash
while true
do
sleep 60
file="/tmp/deadlock-detector-$(date +"%Y-%m-%d-%H-%M-%S").txt"
for pid in $(jps | grep -v Jps | awk '{ print $1 }')
do
jcmd $pid VM.command_line >> $file
jcmd $pid Thread.print >> $file
if jcmd $pid Thread.print | grep -q SimpleLogger
then
# check once more to eliminate most of the sporadic finds
if jcmd $pid Thread.print | grep -q SimpleLogger
then
jcmd $pid GC.heap_dump /tmp/deadlock-detector-$pid.hprof
fi
fi
done
done &

View File

@ -18,12 +18,19 @@ jobs:
with:
job-id: jdk11
- name: Start deadlock detector
run: .github/scripts/deadlock-detector.sh
- name: Build
uses: nick-invision/retry@v2.2.0
run: ./gradlew check --stacktrace -x :smoke-tests:test
- name: Upload deadlock detector artifacts
if: always()
uses: actions/upload-artifact@v2
with:
command: ./gradlew check --stacktrace -x :smoke-tests:test
timeout_minutes: 90
max_attempts: 3
name: deadlock-detector-build
path: /tmp/deadlock-detector-*
if-no-files-found: ignore
test:
runs-on: ubuntu-latest
@ -49,12 +56,19 @@ jobs:
with:
job-id: jdk${{ matrix.java }}
- name: Start deadlock detector
run: .github/scripts/deadlock-detector.sh
- name: Test
uses: nick-invision/retry@v2.2.0
run: ./gradlew test -PtestJavaVersion=${{ matrix.java }} --stacktrace -x :smoke-tests:test -Porg.gradle.java.installations.paths=${{ steps.setup-test-java.outputs.path }} -Porg.gradle.java.installations.auto-download=false
- name: Upload deadlock detector artifacts
if: always()
uses: actions/upload-artifact@v2
with:
command: ./gradlew test -PtestJavaVersion=${{ matrix.java }} --stacktrace -x :smoke-tests:test -Porg.gradle.java.installations.paths=${{ steps.setup-test-java.outputs.path }} -Porg.gradle.java.installations.auto-download=false
timeout_minutes: 90
max_attempts: 3
name: deadlock-detector-test-${{ matrix.java }}
path: /tmp/deadlock-detector-*
if-no-files-found: ignore
smoke-test:
runs-on: ubuntu-latest
@ -72,11 +86,7 @@ jobs:
job-id: smokeTests
- name: Test
uses: nick-invision/retry@v2.2.0
with:
command: ./gradlew :smoke-tests:test
timeout_minutes: 90
max_attempts: 3
run: ./gradlew :smoke-tests:test
setup-muzzle-matrix:
runs-on: ubuntu-latest

View File

@ -54,6 +54,10 @@ See [Writing instrumentation](docs/contributing/writing-instrumentation.md)
See [Understanding the javaagent components](docs/contributing/javaagent-jar-components.md)
### Understanding the javaagent instrumentation testing components
See [Understanding the javaagent instrumentation testing components](docs/contributing/javaagent-test-infra.md)
### Debugging
See [Debugging](docs/contributing/debugging.md)

View File

@ -21,10 +21,6 @@ gradlePlugin {
id = "muzzle"
implementationClass = "MuzzlePlugin"
}
create("javaagent-instrumentation-plugin") {
id = "io.opentelemetry.javaagent.instrumentation-instrumentation"
implementationClass = "io.opentelemetry.instrumentation.gradle.AutoInstrumentationPlugin"
}
}
}

View File

@ -1,61 +0,0 @@
/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
package io.opentelemetry.instrumentation.gradle;
import java.io.File;
import java.util.Arrays;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.plugins.JavaLibraryPlugin;
import org.gradle.api.tasks.Internal;
import org.gradle.api.tasks.testing.Test;
import org.gradle.process.CommandLineArgumentProvider;
/**
* {@link Plugin} to initialize projects that implement auto instrumentation using bytecode
* manipulation. Currently builds the special bootstrap classpath that is needed by bytecode tests.
*/
// TODO(anuraaga): Migrate more build logic into this plugin to avoid having two places for it.
public class AutoInstrumentationPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().apply(JavaLibraryPlugin.class);
project
.getTasks()
.withType(
Test.class,
task -> {
task.dependsOn(":testing-bootstrap:shadowJar");
File testingBootstrapJar =
new File(
project.project(":testing-bootstrap").getBuildDir(),
"libs/testing-bootstrap.jar");
// Make sure tests get rerun if the contents of the testing-bootstrap.jar change
task.getInputs().property("testing-bootstrap-jar", testingBootstrapJar);
task.getJvmArgumentProviders().add(new InstrumentationTestArgs(testingBootstrapJar));
});
}
private static class InstrumentationTestArgs implements CommandLineArgumentProvider {
private final File bootstrapJar;
@Internal
public File getBootstrapJar() {
return bootstrapJar;
}
public InstrumentationTestArgs(File bootstrapJar) {
this.bootstrapJar = bootstrapJar;
}
@Override
public Iterable<String> asArguments() {
return Arrays.asList(
"-Xbootclasspath/a:" + bootstrapJar.getAbsolutePath(), "-Dnet.bytebuddy.raw=true");
}
}
}

View File

@ -1,7 +1,6 @@
### Understanding the javaagent components
OpenTelemetry Auto Instrumentation java agent's jar can logically be divided
into 3 parts:
The javaagent jar can logically be divided into 3 parts:
* Modules that live in the system class loader
* Modules that live in the bootstrap class loader

View File

@ -0,0 +1,38 @@
### Understanding the javaagent instrumentation testing components
Javaagent instrumentation tests are run using a fully shaded `-javaagent` in order to perform
the same bytecode instrumentation as when the agent is run against a normal app.
There are a few key components that make this possible, described below.
### gradle/instrumentation.gradle
* shades the instrumentation
* adds jvm args to the test configuration
* -javaagent:[agent for testing]
* -Dotel.initializer.jar=[shaded instrumentation jar]
The `otel.initializer.jar` property is used to load the shaded instrumentation jar into the
`AgentClassLoader`, so that the javaagent jar doesn't need to be re-built each time.
### :testing:agent-exporter
This contains the span and metric exporters that are used.
These are in-memory exporters, so that the tests can verify the spans and metrics being exported.
These exporters and the in-memory data live in the `AgentClassLoader`, so tests must access them
using reflection. To simplify this, they store the in-memory data using the OTLP protobuf objects,
so that they can be serialized into byte arrays inside the `AgentClassLoader`, then passed back
to the tests and deserialized inside their class loader where they can be verified. The
`:testing-common` module (described below) hides this complexity from instrumentation test authors.
### :agent-for-testing
This is a custom distro of the javaagent that embeds the `:testing:agent-exporter`.
### :testing-common
This module provides methods to help verify the span and metric data produced by the
instrumentation, hiding the complexity of accessing the in-memory exporters that live in the
`AgentClassLoader`.

View File

@ -77,12 +77,12 @@ only depend on the OpenTelemetry API, `instrumentation-common`, and the instrume
[instrumentation-library.gradle](../../gradle/instrumentation-library.gradle) needs to be applied to
configure build tooling for the library.
## Writing unit tests
## Writing instrumentation tests
Once the instrumentation is completed, we add unit tests to the `testing` module. Tests will
Once the instrumentation is completed, we add tests to the `testing` module. Tests will
generally apply to both library and agent instrumentation, with the only difference being how a client
or server is initialized. In a library test, there will be code calling into the instrumentation API,
while in an agent test, it will generally just use the underlying library's API as is. Create unit tests in an
while in an agent test, it will generally just use the underlying library's API as is. Create tests in an
abstract class with an abstract method that returns an instrumented object like a client. The class
should itself extend from `InstrumentationSpecification` to be recognized by Spock and include helper
methods for assertions.
@ -100,11 +100,11 @@ Now that we have working instrumentation, we can implement agent instrumentation
do not have to modify their apps to use it. Make sure the `javaagent` submodule has a dependency on the
`library` submodule and a test dependency on the `testing` submodule. Agent instrumentation defines
classes to match against to generate bytecode for. You will often match against the class you used
in the unit test for library instrumentation, for example the builder of a client. And then you could
in the test for library instrumentation, for example the builder of a client. And then you could
match against the method that creates the builder, for example its constructor. Agent instrumentation
can inject byte code to be run after the constructor returns, which would invoke e.g.,
`registerInterceptor` and initialize the instrumentation. Often, the code inside the byte code
decorator will be identical to the one in the unit test you wrote above - the agent does the work for
decorator will be identical to the one in the test you wrote above - the agent does the work for
initializing the instrumentation library, so a user doesn't have to.
With that written, let's add tests for the agent instrumentation. We basically want to ensure that
@ -113,6 +113,34 @@ the base class you wrote earlier, but in this, create a client using none of the
only the ones offered by the library. Implement the `AgentTestRunner` trait for common setup logic,
and try running. All the tests should pass for agent instrumentation too.
Note that all the tests inside the `javaagent` module will be run using the shaded `-javaagent`
in order to perform the same bytecode instrumentation as when the agent is run against a normal app.
This means that the javaagent instrumentation will be inside the javaagent (inside of the
`AgentClassLoader`) and will not be directly accessible to your test code. See the next section in
case you need to write unit tests that directly access the javaagent instrumentation.
## Writing Java agent unit tests
As mentioned above, tests in the `javaagent` module cannot access the javaagent instrumentation
classes directly.
Ideally javaagent instrumentation is just a thin wrapper over library instrumentation, and so there
is no need to write unit tests that directly access the javaagent instrumentation classes.
If you still want to write a unit test against javaagent instrumentation, add another module
named `javaagent-unittests`. Continuing with the example above:
```
instrumentation ->
...
yarpc-1.0 ->
javaagent
yarpc-1.0-javaagent.gradle
javaagent-unittest
yarpc-1.0-javaagent-unittest.gradle
...
```
### Java agent instrumentation gotchas
#### Calling Java 8 default methods from advice

View File

@ -6,20 +6,15 @@ affecting it negatively, for example introducing crashes.
## Instrumentation tests
All instrumentation are written with instrumentation tests - these can be considered
the unit tests of this project. Instrumentation tests invoke bytecode manipulation to
actually rewrite classes similar to how the agent would in a normal app. By then
exercising the instrumented library in a way a user would, for example by issuing
requests from an HTTP client, we can assert on the spans that should be generated, including
their semantic attributes. A problem in the instrumentation will generally cause
spans to be reported incorrectly or not reported at all, and we can find these situations
with the instrumentation tests.
All instrumentation are written with instrumentation tests - these can be considered the unit tests
of this project.
Note: the instrumentation tests have significant differences from when run against a
normal app with `-javaagent`, in particular, our usual shading is not applied which
can cause false positives. We have work in progress to actually run tests with `-javaagent`
after applying our shading, in which case these tests will run almost identically to
a normal app and eliminate false positives. https://github.com/open-telemetry/opentelemetry-java-instrumentation/pull/1643
Instrumentation tests are run using a fully shaded `-javaagent` in order to perform the same bytecode
instrumentation as when the agent is run against a normal app.
By then exercising the instrumented library in a way a user would, for example by issuing requests
from an HTTP client, we can assert on the spans that should be generated, including their semantic
attributes. A problem in the instrumentation will generally cause spans to be reported incorrectly
or not reported at all, and we can find these situations with the instrumentation tests.
## Latest dep tests

View File

@ -53,4 +53,7 @@ shadowJar {
relocate "io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi"
relocate "io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context"
// relocate OpenTelemetry extensions
relocate "io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin"
relocate "io.opentelemetry.extension.trace.propagation", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.trace.propagation"
}

View File

@ -8,28 +8,28 @@ configurations.all {
ext {
versions = [
opentelemetry : '0.13.1',
opentelemetryAlpha : "0.13.1-alpha",
opentelemetry : '0.13.1',
opentelemetryAlpha: "0.13.1-alpha",
slf4j : "1.7.30",
guava : "20.0", // Last version to support Java 7
slf4j : "1.7.30",
guava : "20.0", // Last version to support Java 7
spock : "1.3-groovy-$spockGroovyVer",
groovy : groovyVer,
logback : "1.2.3",
bytebuddy : "1.10.18", // Also explicitly specified in buildSrc
scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+)
kotlin : "1.4.0",
coroutines : "1.3.0",
springboot : "2.3.1.RELEASE",
spock : "1.3-groovy-$spockGroovyVer",
groovy : groovyVer,
logback : "1.2.3",
bytebuddy : "1.10.18", // Also explicitly specified in buildSrc
scala : "2.11.12", // Last version to support Java 7 (2.12+ require Java 8+)
kotlin : "1.4.0",
coroutines : "1.3.0",
springboot : "2.3.1.RELEASE",
// TODO(anuraaga): Switch off of milestones, this version fixes compatibility with Spock Unroll
junit5 : "5.7.0-M1",
checkerFramework : "3.6.1",
errorprone : "2.4.0",
nullaway : "0.8.0",
autoValue : "1.7.4",
systemLambda : "1.1.0",
prometheus : "0.9.0"
junit5 : "5.7.0-M1",
checkerFramework : "3.6.1",
errorprone : "2.4.0",
nullaway : "0.8.0",
autoValue : "1.7.4",
systemLambda : "1.1.0",
prometheus : "0.9.0"
]
deps = [
@ -40,6 +40,7 @@ ext {
opentelemetryKotlin : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-kotlin', version: versions.opentelemetry),
opentelemetryTraceProps : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-extension-trace-propagators', version: versions.opentelemetry),
opentelemetrySdk : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk', version: versions.opentelemetry),
opentelemetrySdkMetrics : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-metrics', version: versions.opentelemetryAlpha),
opentelemetryJaeger : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger', version: versions.opentelemetry),
opentelemetryJaegerThrift : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-jaeger-thrift', version: versions.opentelemetry),
opentelemetryOtlp : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-otlp', version: versions.opentelemetry),
@ -49,6 +50,7 @@ ext {
opentelemetryLogging : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-exporter-logging', version: versions.opentelemetry),
opentelemetryProto : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-proto', version: versions.opentelemetry),
opentelemetryResources : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-extension-resources', version: versions.opentelemetry),
opentelemetrySdkTesting : dependencies.create(group: 'io.opentelemetry', name: 'opentelemetry-sdk-testing', version: versions.opentelemetry),
// General
slf4j : "org.slf4j:slf4j-api:${versions.slf4j}",

View File

@ -1,9 +1,9 @@
// common gradle file for instrumentation
import io.opentelemetry.instrumentation.gradle.bytebuddy.ByteBuddyPluginConfigurator
apply plugin: 'io.opentelemetry.javaagent.instrumentation-instrumentation'
apply plugin: 'net.bytebuddy.byte-buddy'
apply plugin: 'muzzle'
apply plugin: 'com.github.johnrengelman.shadow'
ext {
packageInAgentBundle = true
@ -23,28 +23,24 @@ if (projectDir.name == 'javaagent') {
afterEvaluate {
dependencies {
implementation project(':instrumentation-api')
implementation project(':javaagent-api')
compileOnly project(':instrumentation-api')
compileOnly project(':javaagent-api')
compileOnly project(':javaagent-bootstrap')
// Apply common dependencies for instrumentation.
implementation(project(':javaagent-tooling')) {
// OpenTelemetry SDK is not needed for compilation, and :opentelemetry-sdk-shaded-for-testing
// is brought in for tests by project(:testing-common) below
compileOnly(project(':javaagent-tooling')) {
// OpenTelemetry SDK is not needed for compilation
exclude group: 'io.opentelemetry', module: 'opentelemetry-sdk'
}
implementation deps.bytebuddy
compileOnly deps.bytebuddy
annotationProcessor deps.autoservice
implementation deps.autoservice
implementation deps.slf4j
compileOnly deps.autoservice
compileOnly deps.slf4j
// Include instrumentations instrumenting core JDK classes tp ensure interoperability with other instrumentation
testImplementation project(':instrumentation:executors:javaagent')
// FIXME: we should enable this, but currently this fails tests for google http client
//testImplementation project(':instrumentation:http-url-connection:javaagent')
testImplementation project(':instrumentation:classloaders:javaagent')
testImplementation deps.opentelemetryApi
testImplementation project(':testing-common')
testAnnotationProcessor deps.autoservice
testImplementation deps.autoservice
testCompileOnly deps.autoservice
testImplementation project(':utils:test-utils')
testImplementation deps.testcontainers
@ -55,3 +51,63 @@ afterEvaluate {
project(':javaagent-tooling').configurations.instrumentationMuzzle + configurations.runtimeClasspath
).configure()
}
configurations {
testInstrumentation
}
shadowJar {
configurations = [project.configurations.runtimeClasspath, project.configurations.testInstrumentation]
mergeServiceFiles()
archiveFileName = 'agent-testing.jar'
// rewrite library instrumentation dependencies
relocate "io.opentelemetry.instrumentation", "io.opentelemetry.javaagent.shaded.instrumentation"
// Prevents conflict with other SLF4J instances. Important for premain.
relocate 'org.slf4j', 'io.opentelemetry.javaagent.slf4j'
// rewrite dependencies calling Logger.getLogger
relocate 'java.util.logging.Logger', 'io.opentelemetry.javaagent.bootstrap.PatchLogger'
// prevents conflict with library instrumentation
relocate 'io.opentelemetry.instrumentation.api', 'io.opentelemetry.javaagent.shaded.instrumentation.api'
// relocate OpenTelemetry API usage
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
relocate "io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi"
relocate "io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context"
// relocate OpenTelemetry extensions
relocate "io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin"
relocate "io.opentelemetry.extension.trace.propagation", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.trace.propagation"
// this is for instrumentation on opentelemetry-api itself
relocate "application.io.opentelemetry", "io.opentelemetry"
}
tasks.withType(Test).configureEach {
jvmArgs "-Dotel.javaagent.debug=true"
jvmArgs "-javaagent:${project(":testing:agent-for-testing").buildDir}/libs/javaagent-for-testing.jar"
jvmArgs "-Dotel.initializer.jar=${shadowJar.archiveFile.get().asFile.absolutePath}"
jvmArgs "-Dinternal.testing.disable.global.library.ignores=true"
dependsOn shadowJar
dependsOn ":testing:agent-for-testing:shadowJar"
// The sources are packaged into the testing jar so we need to make sure to exclude from the test
// classpath, which automatically inherits them, to ensure our shaded versions are used.
classpath = classpath.filter {
if (file("$buildDir/resources/main").equals(it) || file("$buildDir/classes/java/main").equals(it)) {
return false
}
return true
}
}
configurations.configureEach {
if (it.name.toLowerCase().endsWith('testruntimeclasspath')) {
// Added by agent, don't let Gradle bring it in when running tests.
exclude module: 'javaagent-bootstrap'
}
}

View File

@ -26,7 +26,8 @@ def applyCodeCoverage = !(
project.path == ":javaagent" ||
project.path == ":load-generator" ||
project.path.startsWith(":benchmark") ||
project.path.startsWith(":instrumentation"))
project.path.startsWith(":instrumentation") ||
project.path.startsWith(":testing-common"))
if (applyCodeCoverage) {
apply from: "$rootDir/gradle/jacoco.gradle"

View File

@ -15,4 +15,8 @@ dependencies {
testImplementation deps.scala
testImplementation group: 'com.typesafe.akka', name: 'akka-actor_2.11', version: '2.5.0'
}
tasks.withType(Test) {
jvmArgs '-Dotel.instrumentation.akka-actor.enabled=true'
}

View File

@ -24,10 +24,6 @@ import spock.lang.Shared
*/
class AkkaExecutorInstrumentationTest extends AgentTestRunner {
static {
System.setProperty("otel.instrumentation.akka-actor.enabled", "true")
}
@Shared
def executeRunnable = { e, c -> e.execute((Runnable) c) }
@Shared

View File

@ -6,15 +6,15 @@
import akka.actor.{Actor, ActorLogging, ActorRef, ActorSystem, Props}
import akka.pattern.ask
import akka.util.Timeout
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge
import io.opentelemetry.javaagent.testing.common.Java8BytecodeBridge
import scala.concurrent.duration._
// ! == send-message
object AkkaActors {
val tracer: Tracer =
Java8BytecodeBridge.getGlobalTracer("io.opentelemetry.auto")
val tracer: Tracer = GlobalOpenTelemetry.getTracer("io.opentelemetry.auto")
val system: ActorSystem = ActorSystem("helloAkka")

View File

@ -21,8 +21,8 @@ dependencies {
testLibrary group: 'org.apache.camel', name: 'camel-jaxb-starter', version: '2.20.1'
testLibrary group: 'org.apache.camel', name: 'camel-undertow', version: '2.20.1'
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-2.0:javaagent')
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpclient:apache-httpclient-2.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testImplementation group: 'org.spockframework', name: 'spock-spring', version: "$versions.spock"

View File

@ -38,3 +38,7 @@ dependencies {
testImplementation project(':instrumentation:aws-lambda-1.0:testing')
}
tasks.withType(Test) {
jvmArgs '-Dotel.propagators=tracecontext,xray'
}

View File

@ -9,11 +9,12 @@ import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import io.opentelemetry.instrumentation.awslambda.v1_0.AbstractAwsLambdaRequestHandlerTest
import io.opentelemetry.instrumentation.test.AgentTestTrait
import io.opentelemetry.javaagent.testing.common.AgentTestingExporterAccess
class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements AgentTestTrait {
def cleanup() {
assert testWriter.forceFlushCalled()
assert AgentTestingExporterAccess.forceFlushCalled()
}
static class TestRequestHandler implements RequestHandler<String, String> {

View File

@ -8,10 +8,22 @@ package io.opentelemetry.instrumentation.awslambda.v1_0
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import com.amazonaws.services.lambda.runtime.events.SQSEvent
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.context.propagation.TextMapPropagator
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator
import io.opentelemetry.instrumentation.test.InstrumentationTestTrait
class AwsLambdaSqsHandlerTest extends AbstractAwsLambdaSqsHandlerTest implements InstrumentationTestTrait {
// Lambda instrumentation requires XRay propagator to be enabled.
static {
def propagators = ContextPropagators.create(
TextMapPropagator.composite(W3CTraceContextPropagator.instance, AwsXRayPropagator.instance))
OpenTelemetry.setGlobalPropagators(propagators)
}
static class TestHandler extends TracingSqsEventHandler {
@Override
protected void handleEvent(SQSEvent event, Context context) {

View File

@ -7,12 +7,24 @@ package io.opentelemetry.instrumentation.awslambda.v1_0
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.context.propagation.TextMapPropagator
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator
import io.opentelemetry.instrumentation.test.InstrumentationTestTrait
class AwsLambdaTest extends AbstractAwsLambdaRequestHandlerTest implements InstrumentationTestTrait {
// Lambda instrumentation requires XRay propagator to be enabled.
static {
def propagators = ContextPropagators.create(
TextMapPropagator.composite(W3CTraceContextPropagator.instance, AwsXRayPropagator.instance))
OpenTelemetry.setGlobalPropagators(propagators)
}
def cleanup() {
assert testWriter.forceFlushCalled()
assert forceFlushCalled()
}
static class TestRequestHandler extends TracingRequestHandler<String, String> {

View File

@ -26,7 +26,6 @@ dependencies {
implementation deps.groovy
implementation deps.opentelemetryApi
implementation deps.opentelemetryTraceProps
implementation deps.spock
implementation deps.systemLambda
}

View File

@ -10,25 +10,11 @@ import static io.opentelemetry.api.trace.Span.Kind.SERVER
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import com.github.stefanbirkner.systemlambda.SystemLambda
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.attributes.SemanticAttributes
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.context.propagation.TextMapPropagator
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
abstract class AbstractAwsLambdaRequestHandlerTest extends InstrumentationSpecification {
// Lambda instrumentation requires XRay propagator to be enabled.
static {
def propagators = ContextPropagators.create(
TextMapPropagator.composite(
W3CTraceContextPropagator.instance,
AwsXRayPropagator.instance))
OpenTelemetry.setGlobalPropagators(propagators)
}
protected static String doHandleRequest(String input, Context context) {
if (input == "hello") {
return "world"

View File

@ -11,25 +11,11 @@ import static io.opentelemetry.api.trace.Span.Kind.SERVER
import com.amazonaws.services.lambda.runtime.Context
import com.amazonaws.services.lambda.runtime.RequestHandler
import com.amazonaws.services.lambda.runtime.events.SQSEvent
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.attributes.SemanticAttributes
import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.propagation.ContextPropagators
import io.opentelemetry.context.propagation.TextMapPropagator
import io.opentelemetry.extension.trace.propagation.AwsXRayPropagator
import io.opentelemetry.instrumentation.test.InstrumentationSpecification
abstract class AbstractAwsLambdaSqsHandlerTest extends InstrumentationSpecification {
// Lambda instrumentation requires XRay propagator to be enabled.
static {
def propagators = ContextPropagators.create(
TextMapPropagator.composite(
W3CTraceContextPropagator.instance,
AwsXRayPropagator.instance))
OpenTelemetry.setGlobalPropagators(propagators)
}
private static final String AWS_TRACE_HEADER = "Root=1-5759e988-bd862e3fe1be46a994272793;Parent=53995c3f42cd8ad8;Sampled=1"
abstract RequestHandler<SQSEvent, Void> handler()

View File

@ -48,7 +48,7 @@ dependencies {
library group: 'com.amazonaws', name: 'aws-java-sdk-core', version: '1.11.0'
// Include httpclient instrumentation for testing because it is a dependency for aws-sdk.
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testLibrary group: 'com.amazonaws', name: 'aws-java-sdk-s3', version: '1.11.106'
testLibrary group: 'com.amazonaws', name: 'aws-java-sdk-rds', version: '1.11.106'
testLibrary group: 'com.amazonaws', name: 'aws-java-sdk-ec2', version: '1.11.106'

View File

@ -9,9 +9,7 @@ muzzle {
}
dependencies {
implementation(project(':instrumentation:aws-sdk:aws-sdk-2.2:library')) {
exclude group: 'io.opentelemetry', module: 'opentelemetry-extension-trace-propagators'
}
implementation project(':instrumentation:aws-sdk:aws-sdk-2.2:library')
library group: 'software.amazon.awssdk', name: 'aws-core', version: '2.2.0'
@ -19,6 +17,4 @@ dependencies {
// Make sure these don't add HTTP headers
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
testImplementation deps.opentelemetryTraceProps
}

View File

@ -36,8 +36,16 @@ muzzle {
dependencies {
library group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.0.0'
// Need to force version of Guava older than opentelemetry-sdk's implicit dependency to have one
// that is compatible with Cassandra.
testImplementation("com.google.guava:guava") {
version {
strictly("20.0")
}
}
testLibrary group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.2.0'
testImplementation project(':instrumentation:guava-10.0:javaagent')
testInstrumentation project(':instrumentation:guava-10.0:javaagent')
latestDepTestLibrary group: 'com.datastax.cassandra', name: 'cassandra-driver-core', version: '3.+'
}

View File

@ -4,4 +4,12 @@ dependencies {
compileOnly project(':javaagent-bootstrap')
testImplementation project(':javaagent-bootstrap')
}
// TODO (trask) ResourceInjectionTest is sort of hybrid integration/unit test
// maybe cleaner turning it into integration test with its own test instrumentation,
// similar to :testing-common:integration-tests
// then wouldn't need this shadowJar and wouldn't need HelperInjectorAccess
shadowJar {
from("src/test/resources/")
}

View File

@ -6,7 +6,7 @@
import static io.opentelemetry.instrumentation.util.gc.GcUtils.awaitGc
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.javaagent.tooling.HelperInjector
import io.opentelemetry.javaagent.testing.common.HelperInjectorAccess
import java.lang.ref.WeakReference
import java.util.concurrent.atomic.AtomicReference
@ -15,7 +15,6 @@ class ResourceInjectionTest extends AgentTestRunner {
def "resources injected to non-delegating classloader"() {
setup:
String resourceName = 'test-resources/test-resource.txt'
HelperInjector injector = new HelperInjector("test", [], [resourceName])
AtomicReference<URLClassLoader> emptyLoader = new AtomicReference<>(new URLClassLoader(new URL[0], (ClassLoader) null))
when:
@ -26,7 +25,7 @@ class ResourceInjectionTest extends AgentTestRunner {
when:
URLClassLoader notInjectedLoader = new URLClassLoader(new URL[0], (ClassLoader) null)
injector.transform(null, null, emptyLoader.get(), null)
HelperInjectorAccess.injectResources(emptyLoader.get(), resourceName)
resourceUrls = emptyLoader.get().getResources(resourceName)
then:

View File

@ -4,7 +4,6 @@
*/
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.javaagent.instrumentation.api.concurrent.State
import org.apache.catalina.WebResource
import org.apache.catalina.WebResourceRoot
import org.apache.catalina.loader.ParallelWebappClassLoader
@ -25,11 +24,8 @@ class TomcatClassloadingTest extends AgentTestRunner {
classloader.init()
classloader.start()
when:
expect:
// If instrumentation didn't work this would blow up with NPE due to incomplete resources mocking
def clazz = classloader.loadClass("io.opentelemetry.javaagent.instrumentation.api.concurrent.State")
then:
clazz == State
classloader.loadClass("io.opentelemetry.javaagent.instrumentation.api.concurrent.State")
}
}

View File

@ -21,7 +21,7 @@ dependencies {
library group: 'com.couchbase.client', name: 'java-client', version: '2.6.0'
testImplementation project(':instrumentation:couchbase:couchbase-2.0:javaagent')
testInstrumentation project(':instrumentation:couchbase:couchbase-2.0:javaagent')
testImplementation project(':instrumentation:couchbase:couchbase-testing')
testLibrary group: 'org.springframework.data', name: 'spring-data-couchbase', version: '3.1.0.RELEASE'

View File

@ -1,11 +1,17 @@
ext {
skipPublish = true
}
ext.skipPublish = true
apply from: "$rootDir/gradle/instrumentation.gradle"
dependencies {
testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-jersey-2.0:javaagent')
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-jersey-2.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
// Need to force version of Guava older than opentelemetry-sdk's implicit dependency to have one
// that is compatible with Dropwizard.
testImplementation("com.google.guava:guava") {
version {
strictly("20.0")
}
}
// First version with DropwizardTestSupport:
testImplementation group: 'io.dropwizard', name: 'dropwizard-testing', version: '0.8.0'

View File

@ -25,8 +25,8 @@ dependencies {
implementation project(':instrumentation:elasticsearch:elasticsearch-rest-common:javaagent')
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testImplementation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testInstrumentation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'

View File

@ -25,11 +25,11 @@ dependencies {
implementation project(':instrumentation:elasticsearch:elasticsearch-rest-common:javaagent')
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testImplementation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testInstrumentation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
//TODO: review the following claim, we are not using embedded ES anymore
// Netty is used, but it adds complexity to the tests since we're using embedded ES.
//testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
//testInstrumentation project(':instrumentation:netty:netty-4.1:javaagent')
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'

View File

@ -21,9 +21,9 @@ dependencies {
implementation project(':instrumentation:elasticsearch:elasticsearch-transport-common:javaagent')
// Ensure no cross interference
testImplementation project(':instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent')
testImplementation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
testInstrumentation project(':instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testInstrumentation project(':instrumentation:netty:netty-4.1:javaagent')
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'

View File

@ -20,9 +20,9 @@ dependencies {
implementation project(':instrumentation:elasticsearch:elasticsearch-transport-common:javaagent')
testImplementation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
testImplementation project(':instrumentation:spring:spring-data-1.8:javaagent')
testInstrumentation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testInstrumentation project(':instrumentation:netty:netty-4.1:javaagent')
testInstrumentation project(':instrumentation:spring:spring-data-1.8:javaagent')
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-core', version: '2.11.0'
testImplementation group: 'org.apache.logging.log4j', name: 'log4j-api', version: '2.11.0'

View File

@ -29,9 +29,9 @@ dependencies {
implementation project(':instrumentation:elasticsearch:elasticsearch-transport-common:javaagent')
// Ensure no cross interference
testImplementation project(':instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent')
testImplementation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
testInstrumentation project(':instrumentation:elasticsearch:elasticsearch-rest-5.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpasyncclient-4.1:javaagent')
testInstrumentation project(':instrumentation:netty:netty-4.1:javaagent')
testLibrary group: 'org.elasticsearch.plugin', name: 'transport-netty4-client', version: '6.0.0'

View File

@ -5,3 +5,7 @@ muzzle {
coreJdk()
}
}
tasks.withType(Test) {
jvmArgs "-Dotel.instrumentation.executors.include=ExecutorInstrumentationTest\$CustomThreadPoolExecutor"
}

View File

@ -6,7 +6,6 @@
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import io.opentelemetry.sdk.trace.data.SpanData
import java.lang.reflect.InvocationTargetException
import java.util.concurrent.AbstractExecutorService
@ -26,13 +25,6 @@ import java.util.concurrent.TimeoutException
import spock.lang.Shared
class ExecutorInstrumentationTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.executors.include", "ExecutorInstrumentationTest\$CustomThreadPoolExecutor")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
@Shared
def executeRunnable = { e, c -> e.execute((Runnable) c) }

View File

@ -0,0 +1,8 @@
apply from: "$rootDir/gradle/java.gradle"
dependencies {
testImplementation project(':instrumentation-api')
testImplementation project(':javaagent-tooling')
testImplementation deps.bytebuddy
testImplementation project(':instrumentation:external-annotations:javaagent')
}

View File

@ -26,15 +26,19 @@ dependencies {
test {
filter {
excludeTestsMatching 'TraceProvidersTest'
excludeTestsMatching 'ConfiguredTraceAnnotationsTest'
excludeTestsMatching 'TracedMethodsExclusionTest'
}
}
// Needs a fresh classloader.
// https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/919
def testTraceProviders = tasks.register('testTraceProviders', Test) {
test.finalizedBy(tasks.register("testIncludeProperty", Test) {
filter {
includeTestsMatching 'TraceProvidersTest'
includeTestsMatching 'ConfiguredTraceAnnotationsTest'
}
}
test.dependsOn(testTraceProviders)
jvmArgs "-Dotel.instrumentation.external-annotations.include=package.Class\$Name;OuterClass\$InterestingMethod"
})
test.finalizedBy(tasks.register("testExcludeMethodsProperty", Test) {
filter {
includeTestsMatching 'TracedMethodsExclusionTest'
}
jvmArgs "-Dotel.instrumentation.external-annotations.exclude-methods=TracedMethodsExclusionTest\$TestClass[excluded,annotatedButExcluded]"
})

View File

@ -4,19 +4,10 @@
*/
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import io.opentelemetry.test.annotation.SayTracedHello
import java.util.concurrent.Callable
class ConfiguredTraceAnnotationsTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.external-annotations.include",
"package.Class\$Name;${OuterClass.InterestingMethod.name}")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "method with disabled NewRelic annotation should be ignored"() {
setup:

View File

@ -4,18 +4,9 @@
*/
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import io.opentracing.contrib.dropwizard.Trace
class TracedMethodsExclusionTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.external-annotations.exclude-methods",
"${TestClass.name}[excluded,annotatedButExcluded]")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
static class TestClass {
//This method is not mentioned in any configuration

View File

@ -28,7 +28,8 @@ dependencies {
// here.
compileOnly group: 'com.twitter', name: 'finatra-http_2.11', version: '2.9.0'
testImplementation project(':instrumentation:netty:netty-4.1:javaagent')
testInstrumentation project(':instrumentation:netty:netty-4.1:javaagent')
testImplementation group: 'com.twitter', name: 'finatra-http_2.11', version: '19.12.0'
testImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.9.10'
// Required for older versions of finatra on JDKs >= 11

View File

@ -12,6 +12,13 @@ muzzle {
dependencies {
compileOnly group: 'org.glassfish.grizzly', name: 'grizzly-http', version: '2.0'
// Need to force version of Guava older than opentelemetry-sdk's implicit dependency to have one
// that is compatible with Grizzly.
testImplementation("com.google.guava:guava") {
version {
strictly("20.0")
}
}
testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
testImplementation group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0'
testLibrary group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: '2.0'
@ -19,3 +26,7 @@ dependencies {
latestDepTestLibrary group: 'org.glassfish.jersey.containers', name: 'jersey-container-grizzly2-http', version: '2.+'
latestDepTestLibrary group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.+'
}
tasks.withType(Test) {
jvmArgs "-Dotel.instrumentation.grizzly.enabled=true"
}

View File

@ -38,10 +38,6 @@ import org.glassfish.grizzly.utils.IdleTimeoutFilter
class GrizzlyFilterchainServerTest extends HttpServerTest<HttpServer> {
static {
System.setProperty("otel.instrumentation.grizzly.enabled", "true")
}
private TCPNIOTransport transport
private TCPNIOServerConnection serverConnection

View File

@ -22,10 +22,6 @@ import org.glassfish.jersey.server.ResourceConfig
class GrizzlyTest extends HttpServerTest<HttpServer> {
static {
System.setProperty("otel.instrumentation.grizzly.enabled", "true")
}
@Override
HttpServer startServer(int port) {
ResourceConfig rc = new ResourceConfig()

View File

@ -21,10 +21,10 @@ dependencies {
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
testImplementation project(':instrumentation:jdbc:javaagent')
testInstrumentation project(':instrumentation:jdbc:javaagent')
// Added to ensure cross compatibility:
testImplementation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
testImplementation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
testLibrary group: 'org.hibernate', name: 'hibernate-core', version: '3.3.0.SP1'
testImplementation group: 'org.hibernate', name: 'hibernate-annotations', version: '3.4.0.GA'

View File

@ -14,10 +14,10 @@ dependencies {
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
testImplementation project(':instrumentation:jdbc:javaagent')
testInstrumentation project(':instrumentation:jdbc:javaagent')
// Added to ensure cross compatibility:
testImplementation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
testImplementation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-4.3:javaagent')
testImplementation group: 'com.h2database', name: 'h2', version: '1.4.197'
testImplementation "javax.xml.bind:jaxb-api:2.2.11"

View File

@ -14,10 +14,10 @@ dependencies {
implementation project(':instrumentation:hibernate:hibernate-common:javaagent')
testImplementation project(':instrumentation:jdbc:javaagent')
testInstrumentation project(':instrumentation:jdbc:javaagent')
// Added to ensure cross compatibility:
testImplementation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
testImplementation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-3.3:javaagent')
testInstrumentation project(':instrumentation:hibernate:hibernate-4.0:javaagent')
testLibrary group: 'org.hibernate', name: 'hibernate-entitymanager', version: '4.3.0.Final'
testImplementation group: 'org.hsqldb', name: 'hsqldb', version: '2.0.0'

View File

@ -14,3 +14,13 @@ dependencies {
library group: 'com.netflix.hystrix', name: 'hystrix-core', version: '1.4.0'
library group: 'io.reactivex', name: 'rxjava', version: '1.0.7'
}
tasks.withType(Test) {
// TODO run tests both with and without experimental span attributes
jvmArgs "-Dotel.instrumentation.hystrix.experimental-span-attributes=true"
// Disable so failure testing below doesn't inadvertently change the behavior.
jvmArgs "-Dhystrix.command.default.circuitBreaker.enabled=false"
// Uncomment for debugging:
// jvmArgs "-Dhystrix.command.default.execution.timeout.enabled=false"
}

View File

@ -8,26 +8,10 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTra
import com.netflix.hystrix.HystrixObservableCommand
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import rx.Observable
import rx.schedulers.Schedulers
class HystrixObservableChainTest extends AgentTestRunner {
static {
// Disable so failure testing below doesn't inadvertently change the behavior.
System.setProperty("hystrix.command.default.circuitBreaker.enabled", "false")
// Uncomment for debugging:
// System.setProperty("hystrix.command.default.execution.timeout.enabled", "false")
}
static final PREVIOUS_CONFIG = ConfigUtils.updateConfig {
it.setProperty("otel.instrumentation.hystrix.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "test command #action"() {
setup:

View File

@ -10,28 +10,12 @@ import com.netflix.hystrix.HystrixObservable
import com.netflix.hystrix.HystrixObservableCommand
import com.netflix.hystrix.exception.HystrixRuntimeException
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
import rx.Observable
import rx.schedulers.Schedulers
class HystrixObservableTest extends AgentTestRunner {
static {
// Disable so failure testing below doesn't inadvertently change the behavior.
System.setProperty("hystrix.command.default.circuitBreaker.enabled", "false")
// Uncomment for debugging:
// System.setProperty("hystrix.command.default.execution.timeout.enabled", "false")
}
static final PREVIOUS_CONFIG = ConfigUtils.updateConfig {
it.setProperty("otel.instrumentation.hystrix.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "test command #action"() {
setup:
@ -62,7 +46,6 @@ class HystrixObservableTest extends AgentTestRunner {
}
expect:
TRANSFORMED_CLASSES_NAMES.contains("HystrixObservableTest\$1")
result == "Hello!"
assertTraces(1) {
@ -157,7 +140,6 @@ class HystrixObservableTest extends AgentTestRunner {
}
expect:
TRANSFORMED_CLASSES_NAMES.contains("HystrixObservableTest\$2")
result == "Fallback!"
assertTraces(1) {
@ -254,7 +236,6 @@ class HystrixObservableTest extends AgentTestRunner {
}
then:
TRANSFORMED_CLASSES_NAMES.contains("HystrixObservableTest\$3")
def err = thrown HystrixRuntimeException
err.cause instanceof IllegalArgumentException

View File

@ -8,28 +8,12 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTra
import com.netflix.hystrix.HystrixCommand
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.BlockingQueue
import java.util.concurrent.LinkedBlockingQueue
import spock.lang.Timeout
@Timeout(10)
class HystrixTest extends AgentTestRunner {
static {
// Disable so failure testing below doesn't inadvertently change the behavior.
System.setProperty("hystrix.command.default.circuitBreaker.enabled", "false")
// Uncomment for debugging:
// System.setProperty("hystrix.command.default.execution.timeout.enabled", "false")
}
static final PREVIOUS_CONFIG = ConfigUtils.updateConfig {
it.setProperty("otel.instrumentation.hystrix.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "test command #action"() {
setup:
@ -48,7 +32,6 @@ class HystrixTest extends AgentTestRunner {
operation(command)
}
expect:
TRANSFORMED_CLASSES_NAMES.contains("HystrixTest\$1")
result == "Hello!"
assertTraces(1) {
@ -111,7 +94,6 @@ class HystrixTest extends AgentTestRunner {
operation(command)
}
expect:
TRANSFORMED_CLASSES_NAMES.contains("HystrixTest\$2")
result == "Fallback!"
assertTraces(1) {

View File

@ -73,6 +73,9 @@ shadowJar {
relocate "io.opentelemetry.api", "io.opentelemetry.javaagent.shaded.io.opentelemetry.api"
relocate "io.opentelemetry.spi", "io.opentelemetry.javaagent.shaded.io.opentelemetry.spi"
relocate "io.opentelemetry.context", "io.opentelemetry.javaagent.shaded.io.opentelemetry.context"
// relocate OpenTelemetry extensions
relocate "io.opentelemetry.extension.kotlin", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.kotlin"
relocate "io.opentelemetry.extension.trace.propagation", "io.opentelemetry.javaagent.shaded.io.opentelemetry.extension.trace.propagation"
// this is for instrumentation on opentelemetry-api itself

View File

@ -19,8 +19,17 @@ dependencies {
compileOnly group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
compileOnly group: 'javax.annotation', name: 'javax.annotation-api', version: '1.3.2'
testImplementation project(':instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-jersey-2.0:javaagent')
testImplementation project(':instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-resteasy-2.0:javaagent')
// Need to force version of Guava older than opentelemetry-sdk's implicit dependency to have one
// that is compatible with Jersey.
testImplementation("com.google.guava:guava") {
version {
strictly("20.0")
}
}
testInstrumentation project(':instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-jersey-2.0:javaagent')
testInstrumentation project(':instrumentation:jaxrs-client:jaxrs-client-2.0:jaxrs-client-2.0-resteasy-2.0:javaagent')
testImplementation group: 'javax.ws.rs', name: 'javax.ws.rs-api', version: '2.0.1'
@ -33,7 +42,7 @@ dependencies {
testImplementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.2.3'
testImplementation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
testInstrumentation project(':instrumentation:apache-httpclient:apache-httpclient-4.0:javaagent')
latestDepTestLibrary group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '2.27'
latestDepTestLibrary group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '2.27'

View File

@ -6,9 +6,6 @@
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.javaagent.instrumentation.api.WeakMap
import io.opentelemetry.javaagent.instrumentation.jaxrs.v1_0.JaxRsAnnotationsTracer
import java.lang.reflect.Method
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HEAD
@ -40,9 +37,8 @@ class JaxRsAnnotations1InstrumentationTest extends AgentTestRunner {
}
}
def "span named '#name' from annotations on class when is not root span"() {
def "span named '#paramName' from annotations on class when is not root span"() {
setup:
def startingCacheSize = spanNames.size()
runUnderServerTrace("test") {
obj.call()
}
@ -64,8 +60,6 @@ class JaxRsAnnotations1InstrumentationTest extends AgentTestRunner {
}
}
}
spanNames.size() == startingCacheSize + 1
spanNames.get(obj.class).size() == 1
when: "multiple calls to the same method"
runUnderServerTrace("test") {
@ -74,8 +68,6 @@ class JaxRsAnnotations1InstrumentationTest extends AgentTestRunner {
}
}
then: "doesn't increase the cache size"
spanNames.size() == startingCacheSize + 1
spanNames.get(obj.class).size() == 1
where:
paramName | obj
@ -129,10 +121,6 @@ class JaxRsAnnotations1InstrumentationTest extends AgentTestRunner {
// "/child/invoke" | new JavaInterfaces.DefaultChildClassOnInterface()
className = getClassName(obj.class)
// JavaInterfaces classes are loaded on a different classloader, so we need to find the right cache instance.
decorator = obj.class.classLoader.loadClass(JaxRsAnnotationsTracer.name).getMethod("tracer").invoke(null)
spanNames = (WeakMap<Class, Map<Method, String>>) decorator.spanNames
}
def "no annotations has no effect"() {

View File

@ -16,7 +16,8 @@ dependencies {
implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
// First version with DropwizardTestSupport:

View File

@ -26,7 +26,8 @@ dependencies {
implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testLibrary(group: 'org.jboss.resteasy', name: 'resteasy-undertow', version: '3.0.4.Final') {

View File

@ -26,7 +26,8 @@ dependencies {
implementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-common:javaagent')
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
testImplementation project(':instrumentation:jaxrs:jaxrs-2.0:jaxrs-2.0-testing')
testLibrary(group: 'org.jboss.resteasy', name: 'resteasy-undertow', version: '3.1.0.Final') {

View File

@ -6,9 +6,6 @@
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderServerTrace
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.javaagent.instrumentation.api.WeakMap
import io.opentelemetry.javaagent.instrumentation.jaxrs.v2_0.JaxRsAnnotationsTracer
import java.lang.reflect.Method
import javax.ws.rs.DELETE
import javax.ws.rs.GET
import javax.ws.rs.HEAD
@ -44,7 +41,6 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
@Unroll
def "span named '#paramName' from annotations on class when is not root span"() {
setup:
def startingCacheSize = spanNames.size()
runUnderServerTrace("test") {
obj.call()
}
@ -66,8 +62,6 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
}
}
}
spanNames.size() == startingCacheSize + 1
spanNames.get(obj.class).size() == 1
when: "multiple calls to the same method"
runUnderServerTrace("test") {
@ -76,8 +70,6 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
}
}
then: "doesn't increase the cache size"
spanNames.size() == startingCacheSize + 1
spanNames.get(obj.class).size() == 1
where:
paramName | obj
@ -131,10 +123,6 @@ abstract class JaxRsAnnotationsInstrumentationTest extends AgentTestRunner {
// "GET /child/invoke" | new JavaInterfaces.DefaultChildClassOnInterface()
className = getClassName(obj.class)
// JavaInterfaces classes are loaded on a different classloader, so we need to find the right cache instance.
decorator = obj.class.classLoader.loadClass(JaxRsAnnotationsTracer.name).getMethod("tracer").invoke(null)
spanNames = (WeakMap<Class, Map<Method, String>>) decorator.spanNames
}
def "no annotations has no effect"() {

View File

@ -0,0 +1,5 @@
apply from: "$rootDir/gradle/java.gradle"
dependencies {
testImplementation project(':instrumentation:jdbc:javaagent')
}

View File

@ -22,3 +22,6 @@ dependencies {
latestDepTestLibrary group: 'org.apache.derby', name: 'derby', version: '10.14.+'
}
tasks.withType(Test) {
jvmArgs "-Dotel.instrumentation.jdbc-datasource.enabled=true"
}

View File

@ -12,7 +12,6 @@ import com.zaxxer.hikari.HikariConfig
import com.zaxxer.hikari.HikariDataSource
import io.opentelemetry.api.trace.attributes.SemanticAttributes
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.sql.CallableStatement
import java.sql.Connection
import java.sql.PreparedStatement
@ -30,13 +29,6 @@ import test.TestConnection
import test.TestDriver
class JdbcInstrumentationTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.jdbc-datasource.enabled", "true")
}
def specCleanup() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
@Shared
def dbName = "jdbcUnitTest"

View File

@ -20,7 +20,7 @@ dependencies {
testImplementation group: 'com.github.kstyrc', name: 'embedded-redis', version: '0.6'
// ensures jedis-1.4 instrumentation does not load with jedis 3.0+ by failing
// the tests in the event it does. The tests will end up with double spans
testImplementation project(':instrumentation:jedis:jedis-1.4:javaagent')
testInstrumentation project(':instrumentation:jedis:jedis-1.4:javaagent')
testLibrary group: 'redis.clients', name: 'jedis', version: '3.+'
}

View File

@ -18,17 +18,21 @@ class SpringListenerJms2Test extends AgentTestRunner {
def context = new AnnotationConfigApplicationContext(Config)
def factory = context.getBean(ConnectionFactory)
def template = new JmsTemplate(factory)
// TODO(anuraaga): There is no defined order between when JMS starts receiving and our attempt
// to send/receive. Sleep a bit to let JMS start to receive first. Ideally, we would not have
// an ordering constraint in our assertTraces for when there is no defined ordering like this
// test case.
template.convertAndSend("SpringListenerJms2", "a message")
expect:
assertTraces(2) {
trace(0, 2) {
trace(0, 1) {
consumerSpan(it, 0, "queue", "SpringListenerJms2", "", null, "receive")
}
trace(1, 2) {
producerSpan(it, 0, "queue", "SpringListenerJms2")
consumerSpan(it, 1, "queue", "SpringListenerJms2", "", span(0), "process")
}
trace(1, 1) {
consumerSpan(it, 0, "queue", "SpringListenerJms2", "", null, "receive")
}
}
cleanup:

View File

@ -119,16 +119,16 @@ class SpringTemplateJms2Test extends AgentTestRunner {
receivedMessage.text == "responded!"
assertTraces(4) {
trace(0, 1) {
producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
}
trace(1, 1) {
producerSpan(it, 0, destinationType, destinationName)
}
trace(2, 1) {
producerSpan(it, 0, "queue", "(temporary)")
consumerSpan(it, 0, "queue", "(temporary)", receivedMessage.getJMSMessageID(), null, "receive")
}
trace(3, 1) {
consumerSpan(it, 0, "queue", "(temporary)", receivedMessage.getJMSMessageID(), null, "receive")
producerSpan(it, 0, "queue", "(temporary)")
}
}

View File

@ -19,17 +19,22 @@ class SpringListenerJms1Test extends AgentTestRunner {
def context = new AnnotationConfigApplicationContext(Config)
def factory = context.getBean(ConnectionFactory)
def template = new JmsTemplate(factory)
// TODO(anuraaga): There is no defined order between when JMS starts receiving and our attempt
// to send/receive. Sleep a bit to let JMS start to receive first. Ideally, we would not have
// an ordering constraint in our assertTraces for when there is no defined ordering like this
// test case.
sleep(500)
template.convertAndSend("SpringListenerJms1", "a message")
expect:
assertTraces(2) {
trace(0, 2) {
trace(0, 1) {
consumerSpan(it, 0, "queue", "SpringListenerJms1", "", null, "receive")
}
trace(1, 2) {
producerSpan(it, 0, "queue", "SpringListenerJms1")
consumerSpan(it, 1, "queue", "SpringListenerJms1", "", span(0), "process")
}
trace(1, 1) {
consumerSpan(it, 0, "queue", "SpringListenerJms1", "", null, "receive")
}
}
cleanup:

View File

@ -98,17 +98,17 @@ class SpringTemplateJms1Test extends AgentTestRunner {
receivedMessage.text == "responded!"
assertTraces(4) {
trace(0, 1) {
producerSpan(it, 0, destinationType, destinationName)
}
trace(1, 1) {
consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
}
trace(1, 1) {
producerSpan(it, 0, destinationType, destinationName)
}
trace(2, 1) {
// receive doesn't propagate the trace, so this is a root
producerSpan(it, 0, "queue", "(temporary)")
consumerSpan(it, 0, "queue", "(temporary)", receivedMessage.getJMSMessageID(), null, "receive")
}
trace(3, 1) {
consumerSpan(it, 0, "queue", "(temporary)", receivedMessage.getJMSMessageID(), null, "receive")
// receive doesn't propagate the trace, so this is a root
producerSpan(it, 0, "queue", "(temporary)")
}
}

View File

@ -15,7 +15,7 @@ dependencies {
compileOnly group: 'javax.servlet.jsp', name: 'javax.servlet.jsp-api', version: '2.3.0'
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '3.1.0'
testImplementation project(':instrumentation:servlet:servlet-3.0:javaagent')
testInstrumentation project(':instrumentation:servlet:servlet-3.0:javaagent')
// using tomcat 7.0.37 because there seems to be some issues with Tomcat's jar scanning in versions < 7.0.37
// https://stackoverflow.com/questions/23484098/org-apache-tomcat-util-bcel-classfile-classformatexception-invalid-byte-tag-in
testLibrary group: 'org.apache.tomcat.embed', name: 'tomcat-embed-core', version: '7.0.37'
@ -28,3 +28,12 @@ dependencies {
latestDepTestLibrary group: 'org.apache.tomcat.embed', name: 'tomcat-embed-jasper', version: '9.+'
latestDepTestLibrary group: 'org.apache.tomcat.embed', name: 'tomcat-embed-logging-juli', version: '9.+'
}
tasks.withType(Test) {
// skip jar scanning using environment variables:
// http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html#JAR_Scanning
// having this set allows us to test with old versions of the tomcat api since
// JarScanFilter did not exist in the tomcat 7 api
jvmArgs '-Dorg.apache.catalina.startup.ContextConfig.jarsToSkip=*'
jvmArgs '-Dorg.apache.catalina.startup.TldConfig.jarsToSkip=*'
}

View File

@ -24,15 +24,6 @@ import spock.lang.Unroll
//TODO should this be HttpServerTest?
class JspInstrumentationBasicTests extends AgentTestRunner {
static {
// skip jar scanning using environment variables:
// http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html#JAR_Scanning
// having this set allows us to test with old versions of the tomcat api since
// JarScanFilter did not exist in the tomcat 7 api
System.setProperty("org.apache.catalina.startup.ContextConfig.jarsToSkip", "*")
System.setProperty("org.apache.catalina.startup.TldConfig.jarsToSkip", "*")
}
@Shared
int port
@Shared

View File

@ -21,15 +21,6 @@ import spock.lang.Unroll
class JspInstrumentationForwardTests extends AgentTestRunner {
static {
// skip jar scanning using environment variables:
// http://tomcat.apache.org/tomcat-7.0-doc/config/systemprops.html#JAR_Scanning
// having this set allows us to test with old versions of the tomcat api since
// JarScanFilter did not exist in the tomcat 7 api
System.setProperty("org.apache.catalina.startup.ContextConfig.jarsToSkip", "*")
System.setProperty("org.apache.catalina.startup.TldConfig.jarsToSkip", "*")
}
@Shared
int port
@Shared

View File

@ -28,3 +28,19 @@ dependencies {
latestDepTestLibrary group: 'org.springframework.kafka', name: 'spring-kafka-test', version: '2.2.+'
latestDepTestLibrary group: 'org.assertj', name: 'assertj-core', version: '3.+'
}
tasks.withType(Test) {
// TODO run tests both with and without experimental span attributes
jvmArgs "-Dotel.instrumentation.kafka.experimental-span-attributes=true"
}
test {
filter {
excludeTestsMatching 'KafkaClientPropagationDisabledTest'
}
}
test.finalizedBy(tasks.register("testPropagationDisabled", Test) {
filter {
includeTestsMatching 'KafkaClientPropagationDisabledTest'
}
jvmArgs "-Dotel.instrumentation.kafka.client-propagation=false"
})

View File

@ -22,9 +22,8 @@ abstract class KafkaClientBaseTest extends AgentTestRunner {
protected static final SHARED_TOPIC = "shared.topic"
protected isPropagationEnabled() {
return true
}
private static final boolean propagationEnabled = Boolean.parseBoolean(
System.getProperty("otel.instrumentation.kafka.client-propagation", "true"))
@Rule
KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, SHARED_TOPIC)
@ -73,7 +72,7 @@ abstract class KafkaClientBaseTest extends AgentTestRunner {
// check that the message was received
def received = records.poll(5, TimeUnit.SECONDS)
received.headers().iterator().hasNext() == isPropagationEnabled()
received.headers().iterator().hasNext() == propagationEnabled
cleanup:
producerFactory.stop()

View File

@ -7,7 +7,6 @@ import static io.opentelemetry.api.trace.Span.Kind.CONSUMER
import static io.opentelemetry.api.trace.Span.Kind.PRODUCER
import io.opentelemetry.api.trace.attributes.SemanticAttributes
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import org.apache.kafka.clients.consumer.ConsumerConfig
@ -21,20 +20,6 @@ import org.springframework.kafka.test.utils.ContainerTestUtils
import org.springframework.kafka.test.utils.KafkaTestUtils
class KafkaClientPropagationDisabledTest extends KafkaClientBaseTest {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.kafka.client-propagation", "false")
// TODO run tests both with and without experimental span attributes
it.setProperty("otel.instrumentation.kafka.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
@Override
protected isPropagationEnabled() {
return false
}
def "should not read remote context when consuming messages if propagation is disabled"() {
setup:

View File

@ -9,7 +9,6 @@ import static io.opentelemetry.instrumentation.test.utils.TraceUtils.basicSpan
import static io.opentelemetry.instrumentation.test.utils.TraceUtils.runUnderTrace
import io.opentelemetry.api.trace.attributes.SemanticAttributes
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import org.apache.kafka.clients.consumer.ConsumerConfig
@ -29,14 +28,6 @@ import org.springframework.kafka.test.utils.ContainerTestUtils
import org.springframework.kafka.test.utils.KafkaTestUtils
class KafkaClientPropagationEnabledTest extends KafkaClientBaseTest {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
// TODO run tests both with and without experimental span attributes
it.setProperty("otel.instrumentation.kafka.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "test kafka produce and consume"() {
setup:

View File

@ -12,7 +12,7 @@ dependencies {
library group: 'org.apache.kafka', name: 'kafka-streams', version: '0.11.0.0'
// Include kafka-clients instrumentation for tests.
testImplementation project(':instrumentation:kafka-clients-0.11:javaagent')
testInstrumentation project(':instrumentation:kafka-clients-0.11:javaagent')
testLibrary group: 'org.apache.kafka', name: 'kafka-clients', version: '0.11.0.0'
testLibrary group: 'org.springframework.kafka', name: 'spring-kafka', version: '1.3.3.RELEASE'
@ -33,3 +33,8 @@ dependencies {
latestDepTestLibrary group: 'org.springframework.kafka', name: 'spring-kafka-test', version: '2.2.+'
latestDepTestLibrary group: 'org.assertj', name: 'assertj-core', version: '3.+'
}
tasks.withType(Test) {
// TODO run tests both with and without experimental span attributes
jvmArgs "-Dotel.instrumentation.kafka.experimental-span-attributes=true"
}

View File

@ -12,7 +12,6 @@ import io.opentelemetry.api.trace.propagation.W3CTraceContextPropagator
import io.opentelemetry.context.Context
import io.opentelemetry.context.propagation.TextMapPropagator
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.TimeUnit
import org.apache.kafka.clients.consumer.ConsumerRecord
@ -33,14 +32,6 @@ import org.springframework.kafka.test.utils.KafkaTestUtils
import spock.lang.Shared
class KafkaStreamsTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
// TODO run tests both with and without experimental span attributes
it.setProperty("otel.instrumentation.kafka.experimental-span-attributes", "true")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
static final STREAM_PENDING = "test.pending"
static final STREAM_PROCESSED = "test.processed"

View File

@ -28,6 +28,15 @@ public class KotlinCoroutinesInstrumentationModule extends InstrumentationModule
super("kotlinx-coroutines");
}
@Override
public String[] additionalHelperClassNames() {
return new String[] {
"io.opentelemetry.extension.kotlin.ContextExtensionsKt",
"io.opentelemetry.extension.kotlin.KotlinContextElement",
"io.opentelemetry.extension.kotlin.KotlinContextElement$1"
};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return singletonList(new CoroutineScopeLaunchInstrumentation());

View File

@ -3,9 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
import io.opentelemetry.api.GlobalOpenTelemetry
import io.opentelemetry.api.trace.Tracer
import io.opentelemetry.extension.kotlin.asContextElement
import io.opentelemetry.javaagent.instrumentation.api.Java8BytecodeBridge
import java.util.concurrent.TimeUnit
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineDispatcher
@ -26,8 +26,7 @@ import kotlinx.coroutines.withTimeout
import kotlinx.coroutines.yield
class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) {
// Java8BytecodeBridge is needed in order to support Kotlin which generally targets Java 6 bytecode
val tracer: Tracer = Java8BytecodeBridge.getGlobalTracer("io.opentelemetry.auto")
val tracer: Tracer = GlobalOpenTelemetry.getTracer("io.opentelemetry.auto")
fun tracedAcrossChannels() = runTest {
@ -147,6 +146,7 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) {
}
span.end()
}
suspend fun a2(iter: Long) {
var span = tracer.spanBuilder("a2").startSpan()
span.setAttribute("iter", iter)
@ -155,6 +155,7 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) {
}
span.end()
}
suspend fun b(iter: Long) {
var span = tracer.spanBuilder("b").startSpan()
span.setAttribute("iter", iter)
@ -164,6 +165,7 @@ class KotlinCoroutineTests(private val dispatcher: CoroutineDispatcher) {
}
span.end()
}
suspend fun b2(iter: Long) {
var span = tracer.spanBuilder("b2").startSpan()
span.setAttribute("iter", iter)

View File

@ -0,0 +1,6 @@
apply from: "$rootDir/gradle/java.gradle"
dependencies {
testImplementation project(':instrumentation:kubernetes-client-7.0:javaagent')
testImplementation group: 'io.kubernetes', name: 'client-java-api', version: '7.0.0'
}

View File

@ -16,5 +16,5 @@ dependencies {
testImplementation group: 'com.github.kstyrc', name: 'embedded-redis', version: '0.6'
testImplementation group: 'io.lettuce', name: 'lettuce-core', version: '5.0.0.RELEASE'
testImplementation project(':instrumentation:reactor-3.1:javaagent')
testInstrumentation project(':instrumentation:reactor-3.1:javaagent')
}

View File

@ -17,7 +17,7 @@ dependencies {
testImplementation group: 'com.github.kstyrc', name: 'embedded-redis', version: '0.6'
// Only 5.2+ will have command arguments in the db.statement tag.
testLibrary group: 'io.lettuce', name: 'lettuce-core', version: '5.2.0.RELEASE'
testImplementation project(':instrumentation:reactor-3.1:javaagent')
testInstrumentation project(':instrumentation:reactor-3.1:javaagent')
latestDepTestLibrary group: 'io.lettuce', name: 'lettuce-core', version: '5.+'
}

View File

@ -1 +1,7 @@
apply from: "$rootDir/gradle/instrumentation.gradle"
// not applying $rootDir/gradle/instrumentation.gradle because that brings running tests with agent
// infrastructure, and this module only wants to run unit tests
group = 'io.opentelemetry.javaagent.instrumentation'
apply from: "$rootDir/gradle/java.gradle"
apply from: "$rootDir/gradle/publish.gradle"

View File

@ -5,3 +5,7 @@ muzzle {
coreJdk = true
}
}
tasks.withType(Test) {
jvmArgs "-Dotel.instrumentation.methods.include=package.ClassName[method1,method2];MethodTest\$ConfigTracedCallable[call]"
}

View File

@ -52,6 +52,13 @@ public class MethodInstrumentationModule extends InstrumentationModule {
.collect(Collectors.toList());
}
// the default configuration has empty "otel.instrumentation.methods.include", and so doesn't
// generate any TypeInstrumentation for muzzle to analyze
@Override
protected String[] additionalHelperClassNames() {
return new String[] {"io.opentelemetry.javaagent.instrumentation.methods.MethodTracer"};
}
@Override
public List<TypeInstrumentation> typeInstrumentations() {
return typeInstrumentations;

View File

@ -4,18 +4,9 @@
*/
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import java.util.concurrent.Callable
class MethodTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.methods.include",
"package.ClassName[method1,method2];${ConfigTracedCallable.name}[call]")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
static class ConfigTracedCallable implements Callable<String> {
@Override

View File

@ -18,5 +18,5 @@ dependencies {
testImplementation project(':instrumentation:mongo:mongo-testing')
testImplementation group: 'de.flapdoodle.embed', name: 'de.flapdoodle.embed.mongo', version: '1.50.5'
testImplementation project(':instrumentation:mongo:mongo-3.7:javaagent')
testInstrumentation project(':instrumentation:mongo:mongo-3.7:javaagent')
}

View File

@ -1,5 +1,17 @@
apply from: "$rootDir/gradle/instrumentation.gradle"
// not applying $rootDir/gradle/instrumentation.gradle because that brings running tests with agent
// infrastructure, and this module only wants to run unit tests
group = 'io.opentelemetry.javaagent.instrumentation'
apply from: "$rootDir/gradle/java.gradle"
apply from: "$rootDir/gradle/publish.gradle"
dependencies {
library group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
compileOnly project(':instrumentation-api')
compileOnly project(':javaagent-api')
compileOnly group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
testImplementation project(':instrumentation-api')
testImplementation project(':javaagent-api')
testImplementation group: 'org.mongodb', name: 'mongo-java-driver', version: '3.1.0'
}

View File

@ -43,7 +43,8 @@ class OkHttp3AsyncTest extends OkHttp3Test {
latch.countDown()
}
})
latch.await(20, SECONDS)
// need to wait a while for tests of the connection timeout (20 seconds led to failures in CI)
latch.await(30, SECONDS)
if (exRef.get() != null) {
throw exRef.get()
}

View File

@ -7,5 +7,9 @@ dependencies {
// see the comment in opentelemetry-api-1.0.gradle for more details
compileOnly project(path: ':opentelemetry-ext-annotations-shaded-for-instrumenting', configuration: 'shadow')
testImplementation project(path: ':opentelemetry-ext-annotations-shaded-for-instrumenting', configuration: 'shadow')
testImplementation deps.opentelemetryExtAnnotations
}
test {
jvmArgs "-Dotel.instrumentation.opentelemetry-annotations.exclude-methods=io.opentelemetry.test.annotation.TracedWithSpan[ignored]"
}

View File

@ -9,21 +9,12 @@ import static io.opentelemetry.api.trace.Span.Kind.SERVER
import io.opentelemetry.api.trace.Span
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.instrumentation.test.utils.ConfigUtils
import io.opentelemetry.test.annotation.TracedWithSpan
/**
* This test verifies that auto instrumentation supports {@link io.opentelemetry.extension.annotations.WithSpan} contrib annotation.
*/
class WithSpanInstrumentationTest extends AgentTestRunner {
static final PREVIOUS_CONFIG = ConfigUtils.updateConfigAndResetInstrumentation {
it.setProperty("otel.instrumentation.opentelemetry-annotations.exclude-methods",
"${TracedWithSpan.name}[ignored]")
}
def cleanupSpec() {
ConfigUtils.setConfig(PREVIOUS_CONFIG)
}
def "should derive automatic name"() {
setup:

View File

@ -5,8 +5,8 @@
package io.opentelemetry.test.annotation;
import application.io.opentelemetry.api.trace.Span.Kind;
import application.io.opentelemetry.extension.annotations.WithSpan;
import io.opentelemetry.api.trace.Span.Kind;
import io.opentelemetry.extension.annotations.WithSpan;
public class TracedWithSpan {

View File

@ -23,5 +23,13 @@ dependencies {
// using OpenTelemetry SDK to make sure that instrumentation doesn't cause
// OpenTelemetrySdk.getTracerProvider() to throw ClassCastException
testImplementation project(path: ':opentelemetry-sdk-shaded-for-instrumenting', configuration: 'shadow')
testImplementation deps.opentelemetrySdk
// @WithSpan annotation is used to generate spans in ContextBridgeTest
testImplementation deps.opentelemetryExtAnnotations
testInstrumentation project(':instrumentation:opentelemetry-annotations-1.0:javaagent')
}
tasks.withType(Test) {
jvmArgs '-Dotel.trace.annotated.methods.exclude=io.opentelemetry.test.annotation.TracedWithSpan[ignored]'
}

View File

@ -3,192 +3,150 @@
* SPDX-License-Identifier: Apache-2.0
*/
import application.io.opentelemetry.api.OpenTelemetry
import application.io.opentelemetry.api.baggage.Baggage
import application.io.opentelemetry.api.baggage.BaggageEntryMetadata
import application.io.opentelemetry.api.trace.Span
import application.io.opentelemetry.context.Context
import application.io.opentelemetry.context.ContextKey
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.baggage.Baggage
import io.opentelemetry.api.trace.Span
import io.opentelemetry.context.Context
import io.opentelemetry.context.ContextKey
import io.opentelemetry.extension.annotations.WithSpan
import io.opentelemetry.instrumentation.test.AgentTestRunner
import java.util.concurrent.CountDownLatch
import java.util.concurrent.Executors
import java.util.concurrent.atomic.AtomicReference
class ContextBridgeTest extends AgentTestRunner {
private static final ContextKey<String> ANIMAL = ContextKey.named("animal")
private static final io.opentelemetry.context.ContextKey<String> FOOD =
io.opentelemetry.context.ContextKey.named("food")
private static final io.opentelemetry.context.ContextKey<String> COUNTRY =
io.opentelemetry.context.ContextKey.named("country")
def "agent and application mix"() {
expect:
def agentContext = io.opentelemetry.context.Context.current().with(COUNTRY, "japan")
io.opentelemetry.context.Context.current().get(COUNTRY) == null
agentContext.makeCurrent().withCloseable {
io.opentelemetry.context.Context.current().get(COUNTRY) == "japan"
Context.current().with(ANIMAL, "cat").makeCurrent().withCloseable {
Context.current().get(ANIMAL) == "cat"
io.opentelemetry.context.Context.current().get(COUNTRY) == "japan"
def agentContext2 = io.opentelemetry.context.Context.current().with(FOOD, "cheese")
io.opentelemetry.context.Context.current().get(FOOD) == null
agentContext2.makeCurrent().withCloseable {
io.opentelemetry.context.Context.current().get(FOOD) == "cheese"
io.opentelemetry.context.Context.current().get(COUNTRY) == "japan"
Context.current().get(ANIMAL) == "cat"
}
}
}
}
// The difference between "standard" context interop and our bridge is that with normal interop,
// keys are still isolated completely. We have special logic to share the same data for our known
// types like span.
def "agent and application share span"() {
def "agent propagates application's context"() {
when:
def applicationTracer = OpenTelemetry.getGlobalTracer("test")
def agentTracer = io.opentelemetry.api.OpenTelemetry.getGlobalTracer("test")
def context = Context.current().with(ANIMAL, "cat")
def captured = new AtomicReference<String>()
context.makeCurrent().withCloseable {
Executors.newSingleThreadExecutor().submit({
captured.set(Context.current().get(ANIMAL))
}).get()
}
then:
!Span.current().spanContext.isValid()
!io.opentelemetry.api.trace.Span.current().spanContext.isValid()
def applicationSpan = applicationTracer.spanBuilder("test1").startSpan()
applicationSpan.spanContext.isValid()
applicationSpan.makeCurrent().withCloseable {
Span.current().spanContext.spanIdAsHexString == applicationSpan.spanContext.spanIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.spanIdAsHexString == applicationSpan.spanContext.spanIdAsHexString
def agentSpan = agentTracer.spanBuilder("test2").startSpan()
agentSpan.makeCurrent().withCloseable {
Span.current().spanContext.spanIdAsHexString == agentSpan.spanContext.spanIdAsHexString
Span.current().spanContext.traceIdAsHexString == agentSpan.spanContext.spanIdAsHexString
Span.current().spanContext.traceIdAsHexString == applicationSpan.spanContext.spanIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.spanIdAsHexString == agentSpan.spanContext.spanIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.traceIdAsHexString == agentSpan.spanContext.traceIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.traceIdAsHexString == applicationSpan.spanContext.traceIdAsHexString
def applicationSpan2 = applicationTracer.spanBuilder("test3").startSpan()
applicationSpan2.makeCurrent().withCloseable {
Span.current().spanContext.spanIdAsHexString == applicationSpan2.spanContext.spanIdAsHexString
Span.current().spanContext.traceIdAsHexString == applicationSpan2.spanContext.spanIdAsHexString
Span.current().spanContext.traceIdAsHexString == applicationSpan.spanContext.spanIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.spanIdAsHexString == applicationSpan2.spanContext.spanIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.traceIdAsHexString == applicationSpan2.spanContext.traceIdAsHexString
io.opentelemetry.api.trace.Span.current().spanContext.traceIdAsHexString == applicationSpan.spanContext.traceIdAsHexString
}
}
}
captured.get() == "cat"
}
def "agent and application share baggage"() {
expect:
def applicationBaggage = Baggage.builder()
.put("food", "cheese")
.put("country", "japan", BaggageEntryMetadata.create("asia"))
.build()
applicationBaggage.makeCurrent().withCloseable {
def agentBaggage = io.opentelemetry.api.baggage.Baggage.current()
agentBaggage.asMap().with {
size() == 2
get("food").value == "cheese"
get("food").entryMetadata == io.opentelemetry.api.baggage.BaggageEntryMetadata.empty()
get("country").value == "japan"
get("country").entryMetadata == io.opentelemetry.api.baggage.BaggageEntryMetadata.create("asia")
}
agentBaggage = io.opentelemetry.api.baggage.Baggage.builder()
.put("country", "italy", io.opentelemetry.api.baggage.BaggageEntryMetadata.create("europe"))
.build()
agentBaggage.makeCurrent().withCloseable {
def updatedApplicationBaggage = Baggage.current()
updatedApplicationBaggage.asMap().with {
size() == 2
get("food").value == "cheese"
get("food").entryMetadata == BaggageEntryMetadata.empty()
get("country").value == "italy"
get("country").entryMetadata == BaggageEntryMetadata.create("europe")
}
applicationBaggage = applicationBaggage.toBuilder()
.put("food", "cabbage")
.build()
applicationBaggage.makeCurrent().withCloseable {
agentBaggage = io.opentelemetry.api.baggage.Baggage.current()
agentBaggage.asMap().with {
size() == 2
get("food").value == "cabbage"
get("food").entryMetadata == io.opentelemetry.api.baggage.BaggageEntryMetadata.empty()
get("country").value == "japan"
get("country").entryMetadata == io.opentelemetry.api.baggage.BaggageEntryMetadata.create("asia")
}
}
}
}
}
def "agent wraps"() {
expect:
def agentContext = io.opentelemetry.context.Context.current().with(COUNTRY, "japan")
agentContext.makeCurrent().withCloseable {
Context.current().with(ANIMAL, "cat").makeCurrent().withCloseable {
io.opentelemetry.context.Context.current().get(COUNTRY) == "japan"
Context.current().get(ANIMAL) == "cat"
def agentValue = new AtomicReference<String>()
def applicationValue = new AtomicReference<String>()
Runnable runnable = {
agentValue.set(io.opentelemetry.context.Context.current().get(COUNTRY))
applicationValue.set(Context.current().get(ANIMAL))
}
runnable.run()
agentValue.get() == null
applicationValue.get() == null
def ctx = io.opentelemetry.context.Context.current()
// Simulate another thread by remounting root
def "application propagates agent's context"() {
when:
new Runnable() {
@WithSpan("test")
@Override
void run() {
// using @WithSpan above to make the agent generate a context
// and then using manual propagation below to verify that context can be propagated by user
def context = Context.current()
Context.root().makeCurrent().withCloseable {
io.opentelemetry.context.Context.root().makeCurrent().withCloseable {
ctx.wrap(runnable).run()
Span.current().setAttribute("dog", "no")
context.makeCurrent().withCloseable {
Span.current().setAttribute("cat", "yes")
}
}
}
}.run()
then:
assertTraces(1) {
trace(0, 1) {
span(0) {
name "test"
hasNoParent()
attributes {
"cat" "yes"
}
}
agentValue.get() == "japan"
applicationValue.get() == "cat"
}
}
}
def "application wraps"() {
expect:
def agentContext = io.opentelemetry.context.Context.current().with(COUNTRY, "japan")
agentContext.makeCurrent().withCloseable {
Context.current().with(ANIMAL, "cat").makeCurrent().withCloseable {
io.opentelemetry.context.Context.current().get(COUNTRY) == "japan"
Context.current().get(ANIMAL) == "cat"
def "agent propagates application's span"() {
when:
def tracer = OpenTelemetry.getGlobalTracer("test")
def agentValue = new AtomicReference<String>()
def applicationValue = new AtomicReference<String>()
Runnable runnable = {
agentValue.set(io.opentelemetry.context.Context.current().get(COUNTRY))
applicationValue.set(Context.current().get(ANIMAL))
def testSpan = tracer.spanBuilder("test").startSpan()
testSpan.makeCurrent().withCloseable {
Executors.newSingleThreadExecutor().submit({
Span.current().setAttribute("cat", "yes")
}).get()
}
testSpan.end()
then:
assertTraces(1) {
trace(0, 1) {
span(0) {
name "test"
hasNoParent()
attributes {
"cat" "yes"
}
}
}
}
}
agentValue.get() == null
applicationValue.get() == null
def ctx = Context.current()
// Simulate another thread by remounting root
def "application propagates agent's span"() {
when:
new Runnable() {
@WithSpan("test")
@Override
void run() {
// using @WithSpan above to make the agent generate a span
// and then using manual propagation below to verify that span can be propagated by user
def span = Span.current()
Context.root().makeCurrent().withCloseable {
io.opentelemetry.context.Context.root().makeCurrent().withCloseable {
ctx.wrap(runnable).run()
Span.current().setAttribute("dog", "no")
span.makeCurrent().withCloseable {
Span.current().setAttribute("cat", "yes")
}
}
}
}.run()
then:
assertTraces(1) {
trace(0, 1) {
span(0) {
name "test"
hasNoParent()
attributes {
"cat" "yes"
}
}
agentValue.get() == "japan"
applicationValue.get() == "cat"
}
}
}
def "agent propagates application's baggage"() {
when:
def testBaggage = Baggage.builder().put("cat", "yes").build()
def ref = new AtomicReference<Baggage>()
def latch = new CountDownLatch(1)
testBaggage.makeCurrent().withCloseable {
Executors.newSingleThreadExecutor().submit({
ref.set(Baggage.current())
latch.countDown()
}).get()
}
then:
latch.await()
ref.get().size() == 1
ref.get().getEntryValue("cat") == "yes"
}
// TODO (trask)
// more tests are needed here, not sure how to implement, probably need to write some test
// instrumentation to help test, similar to :testing-common:integration-tests
//
// * "application propagates agent's baggage"
// * "agent uses application's span"
// * "application uses agent's span" (this is covered above by "application propagates agent's span")
// * "agent uses application's baggage"
// * "application uses agent's baggage"
}

View File

@ -3,9 +3,9 @@
* SPDX-License-Identifier: Apache-2.0
*/
import application.io.opentelemetry.api.OpenTelemetry
import application.io.opentelemetry.api.trace.Span
import application.io.opentelemetry.context.Context
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.trace.Span
import io.opentelemetry.context.Context
import io.opentelemetry.instrumentation.test.AgentTestRunner
class ContextTest extends AgentTestRunner {

View File

@ -8,13 +8,13 @@ import static io.opentelemetry.sdk.metrics.data.MetricData.Type.DOUBLE_SUM
import static io.opentelemetry.sdk.metrics.data.MetricData.Type.LONG_GAUGE
import static io.opentelemetry.sdk.metrics.data.MetricData.Type.LONG_SUM
import static io.opentelemetry.sdk.metrics.data.MetricData.Type.SUMMARY
import static java.util.concurrent.TimeUnit.SECONDS
import application.io.opentelemetry.api.OpenTelemetry
import application.io.opentelemetry.api.common.Labels
import application.io.opentelemetry.api.metrics.AsynchronousInstrument
import com.google.common.base.Stopwatch
import io.opentelemetry.api.OpenTelemetry
import io.opentelemetry.api.common.Labels
import io.opentelemetry.api.metrics.AsynchronousInstrument
import io.opentelemetry.instrumentation.test.AgentTestRunner
import io.opentelemetry.sdk.OpenTelemetrySdk
import io.opentelemetry.sdk.metrics.data.MetricData
import java.util.function.Consumer
class MeterTest extends AgentTestRunner {
@ -42,7 +42,7 @@ class MeterTest extends AgentTestRunner {
}
then:
def metricData = findMetric(OpenTelemetrySdk.getGlobalMeterProvider().getMetricProducer().collectAllMetrics(), instrumentationName, "test")
def metricData = findMetric(instrumentationName, "test")
metricData != null
metricData.description == "d"
metricData.unit == "u"
@ -52,9 +52,9 @@ class MeterTest extends AgentTestRunner {
metricData.points.size() == 1
def point = metricData.points.iterator().next()
if (bind) {
point.labels == io.opentelemetry.api.common.Labels.of("w", "x", "y", "z")
point.labels == Labels.of("w", "x", "y", "z")
} else {
point.labels == io.opentelemetry.api.common.Labels.of("q", "r")
point.labels == Labels.of("q", "r")
}
point.value == expectedValue
@ -93,7 +93,7 @@ class MeterTest extends AgentTestRunner {
}
then:
def metricData = findMetric(OpenTelemetrySdk.getGlobalMeterProvider().getMetricProducer().collectAllMetrics(), instrumentationName, "test")
def metricData = findMetric(instrumentationName, "test")
metricData != null
metricData.description == "d"
metricData.unit == "u"
@ -103,9 +103,9 @@ class MeterTest extends AgentTestRunner {
metricData.points.size() == 1
def point = metricData.points.iterator().next()
if (bind) {
point.labels == io.opentelemetry.api.common.Labels.of("w", "x", "y", "z")
point.labels == Labels.of("w", "x", "y", "z")
} else {
point.labels == io.opentelemetry.api.common.Labels.of("q", "r")
point.labels == Labels.of("q", "r")
}
where:
@ -172,7 +172,7 @@ class MeterTest extends AgentTestRunner {
instrument.build()
then:
def metricData = findMetric(OpenTelemetrySdk.getGlobalMeterProvider().getMetricProducer().collectAllMetrics(), instrumentationName, "test")
def metricData = findMetric(instrumentationName, "test")
metricData != null
metricData.description == "d"
metricData.unit == "u"
@ -181,7 +181,7 @@ class MeterTest extends AgentTestRunner {
metricData.instrumentationLibraryInfo.version == "1.2.3"
metricData.points.size() == 1
def point = metricData.points.iterator().next()
point.labels == io.opentelemetry.api.common.Labels.of("q", "r")
point.labels == Labels.of("q", "r")
if (builderMethod.startsWith("long")) {
point.value == 123
} else {
@ -221,10 +221,8 @@ class MeterTest extends AgentTestRunner {
.put(doubleMeasure, 6.6)
.record()
def allMetrics = OpenTelemetrySdk.getGlobalMeterProvider().getMetricProducer().collectAllMetrics()
then:
def metricData = findMetric(allMetrics, instrumentationName, "test")
def metricData = findMetric(instrumentationName, "test")
metricData != null
metricData.description == "d"
metricData.unit == "u"
@ -233,10 +231,10 @@ class MeterTest extends AgentTestRunner {
metricData.instrumentationLibraryInfo.version == "1.2.3"
metricData.points.size() == 1
def point = metricData.points.iterator().next()
point.labels == io.opentelemetry.api.common.Labels.of("q", "r")
point.labels == Labels.of("q", "r")
point.value == 11
def metricData2 = findMetric(allMetrics, instrumentationName, "test2")
def metricData2 = findMetric(instrumentationName, "test2")
metricData2 != null
metricData2.description == "d"
metricData2.unit == "u"
@ -245,15 +243,19 @@ class MeterTest extends AgentTestRunner {
metricData2.instrumentationLibraryInfo.version == "1.2.3"
metricData2.points.size() == 1
def point2 = metricData2.points.iterator().next()
point2.labels == io.opentelemetry.api.common.Labels.of("q", "r")
point2.labels == Labels.of("q", "r")
point2.count == 2
point2.sum == 12.1
}
def findMetric(Collection<MetricData> allMetrics, instrumentationName, metricName) {
for (def metric : allMetrics) {
if (metric.instrumentationLibraryInfo.name == instrumentationName && metric.name == metricName) {
return metric
def findMetric(instrumentationName, metricName) {
Stopwatch stopwatch = Stopwatch.createStarted()
while (stopwatch.elapsed(SECONDS) < 10) {
def allMetrics = TEST_WRITER.getMetrics()
for (def metric : allMetrics) {
if (metric.instrumentationLibraryInfo.name == instrumentationName && metric.name == metricName) {
return metric
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More