Browse Source

Run tests with javaagent. (#1643)

Co-authored-by: Trask Stalnaker <trask.stalnaker@gmail.com>
Anuraag Agrawal 4 years ago
parent
commit
8d74baa2e4
100 changed files with 673 additions and 639 deletions
  1. 20 0
      .github/scripts/deadlock-detector.sh
  2. 23 13
      .github/workflows/pr.yaml
  3. 4 0
      CONTRIBUTING.md
  4. 0 4
      buildSrc/build.gradle
  5. 0 61
      buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java
  6. 1 2
      docs/contributing/javaagent-jar-components.md
  7. 38 0
      docs/contributing/javaagent-test-infra.md
  8. 33 5
      docs/contributing/writing-instrumentation.md
  9. 9 14
      docs/safety-mechanisms.md
  10. 3 0
      examples/distro/instrumentation/build.gradle
  11. 21 19
      gradle/dependencies.gradle
  12. 71 15
      gradle/instrumentation.gradle
  13. 2 1
      gradle/java.gradle
  14. 4 0
      instrumentation/akka-actor-2.5/javaagent/akka-actor-2.5-javaagent.gradle
  15. 0 4
      instrumentation/akka-actor-2.5/javaagent/src/test/groovy/AkkaExecutorInstrumentationTest.groovy
  16. 3 3
      instrumentation/akka-actor-2.5/javaagent/src/test/scala/AkkaActors.scala
  17. 2 2
      instrumentation/apache-camel-2.20/javaagent/apache-camel-2.20-javaagent.gradle
  18. 4 0
      instrumentation/aws-lambda-1.0/javaagent/aws-lambda-1.0-javaagent.gradle
  19. 2 1
      instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy
  20. 12 0
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy
  21. 13 1
      instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy
  22. 0 1
      instrumentation/aws-lambda-1.0/testing/aws-lambda-1.0-testing.gradle
  23. 0 14
      instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaRequestHandlerTest.groovy
  24. 0 14
      instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsHandlerTest.groovy
  25. 1 1
      instrumentation/aws-sdk/aws-sdk-1.11/javaagent/aws-sdk-1.11-javaagent.gradle
  26. 1 5
      instrumentation/aws-sdk/aws-sdk-2.2/javaagent/aws-sdk-2.2-javaagent.gradle
  27. 9 1
      instrumentation/cassandra/cassandra-3.0/javaagent/cassandra-3.0-javaagent.gradle
  28. 8 0
      instrumentation/classloaders/javaagent/classloaders-javaagent.gradle
  29. 2 3
      instrumentation/classloaders/javaagent/src/test/groovy/ResourceInjectionTest.groovy
  30. 2 6
      instrumentation/classloaders/javaagent/tomcat-testing/src/test/groovy/TomcatClassloadingTest.groovy
  31. 1 1
      instrumentation/couchbase/couchbase-2.6/javaagent/couchbase-2.6-javaagent.gradle
  32. 11 5
      instrumentation/dropwizard-testing/dropwizard-testing.gradle
  33. 2 2
      instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/elasticsearch-rest-5.0-javaagent.gradle
  34. 3 3
      instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/elasticsearch-rest-6.4-javaagent.gradle
  35. 3 3
      instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/elasticsearch-transport-5.0-javaagent.gradle
  36. 3 3
      instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/elasticsearch-transport-5.3-javaagent.gradle
  37. 3 3
      instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/elasticsearch-transport-6.0-javaagent.gradle
  38. 4 0
      instrumentation/executors/javaagent/executors-javaagent.gradle
  39. 0 8
      instrumentation/executors/javaagent/src/test/groovy/ExecutorInstrumentationTest.groovy
  40. 8 0
      instrumentation/external-annotations/javaagent-unittests/external-annotations-javaagent-unittests.gradle
  41. 0 0
      instrumentation/external-annotations/javaagent-unittests/src/test/groovy/IncludeTest.groovy
  42. 12 8
      instrumentation/external-annotations/javaagent/external-annotations-javaagent.gradle
  43. 0 9
      instrumentation/external-annotations/javaagent/src/test/groovy/ConfiguredTraceAnnotationsTest.groovy
  44. 0 9
      instrumentation/external-annotations/javaagent/src/test/groovy/TracedMethodsExclusionTest.groovy
  45. 2 1
      instrumentation/finatra-2.9/javaagent/finatra-2.9-javaagent.gradle
  46. 11 0
      instrumentation/grizzly-2.0/javaagent/grizzly-2.0-javaagent.gradle
  47. 0 4
      instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy
  48. 0 4
      instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy
  49. 3 3
      instrumentation/hibernate/hibernate-3.3/javaagent/hibernate-3.3-javaagent.gradle
  50. 3 3
      instrumentation/hibernate/hibernate-4.0/javaagent/hibernate-4.0-javaagent.gradle
  51. 3 3
      instrumentation/hibernate/hibernate-4.3/javaagent/hibernate-4.3-javaagent.gradle
  52. 10 0
      instrumentation/hystrix-1.4/javaagent/hystrix-1.4-javaagent.gradle
  53. 0 16
      instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixObservableChainTest.groovy
  54. 0 19
      instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixObservableTest.groovy
  55. 0 18
      instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixTest.groovy
  56. 3 0
      instrumentation/instrumentation.gradle
  57. 12 3
      instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/jaxrs-client-2.0-common-javaagent.gradle
  58. 1 13
      instrumentation/jaxrs/jaxrs-1.0/javaagent/src/test/groovy/JaxRsAnnotations1InstrumentationTest.groovy
  59. 2 1
      instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/jaxrs-2.0-jersey-2.0-javaagent.gradle
  60. 2 1
      instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/jaxrs-2.0-resteasy-3.0-javaagent.gradle
  61. 2 1
      instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/jaxrs-2.0-resteasy-3.1-javaagent.gradle
  62. 0 12
      instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxRsAnnotationsInstrumentationTest.groovy
  63. 5 0
      instrumentation/jdbc/javaagent-unittests/jdbc-javaagent-unittests.gradle
  64. 0 0
      instrumentation/jdbc/javaagent-unittests/src/test/groovy/JdbcConnectionUrlParserTest.groovy
  65. 3 0
      instrumentation/jdbc/javaagent/jdbc-javaagent.gradle
  66. 0 8
      instrumentation/jdbc/javaagent/src/test/groovy/JdbcInstrumentationTest.groovy
  67. 1 1
      instrumentation/jedis/jedis-3.0/javaagent/jedis-3.0-javaagent.gradle
  68. 8 4
      instrumentation/jms-1.1/javaagent/src/jms2Test/groovy/SpringListenerJms2Test.groovy
  69. 4 4
      instrumentation/jms-1.1/javaagent/src/jms2Test/groovy/SpringTemplateJms2Test.groovy
  70. 9 4
      instrumentation/jms-1.1/javaagent/src/test/groovy/SpringListenerJms1Test.groovy
  71. 5 5
      instrumentation/jms-1.1/javaagent/src/test/groovy/SpringTemplateJms1Test.groovy
  72. 10 1
      instrumentation/jsp-2.3/javaagent/jsp-2.3-javaagent.gradle
  73. 0 9
      instrumentation/jsp-2.3/javaagent/src/test/groovy/JspInstrumentationBasicTests.groovy
  74. 0 9
      instrumentation/jsp-2.3/javaagent/src/test/groovy/JspInstrumentationForwardTests.groovy
  75. 16 0
      instrumentation/kafka-clients-0.11/javaagent/kafka-clients-0.11-javaagent.gradle
  76. 3 4
      instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientBaseTest.groovy
  77. 0 15
      instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientPropagationDisabledTest.groovy
  78. 0 9
      instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientPropagationEnabledTest.groovy
  79. 6 1
      instrumentation/kafka-streams-0.11/javaagent/kafka-streams-0.11-javaagent.gradle
  80. 0 9
      instrumentation/kafka-streams-0.11/javaagent/src/test/groovy/KafkaStreamsTest.groovy
  81. 9 0
      instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java
  82. 5 3
      instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt
  83. 6 0
      instrumentation/kubernetes-client-7.0/javaagent-unittests/kubernetes-client-7.0-javaagent-unittests.gradle
  84. 0 0
      instrumentation/kubernetes-client-7.0/javaagent-unittests/src/test/groovy/KubernetesRequestUtilsTest.groovy
  85. 1 1
      instrumentation/lettuce/lettuce-5.0/javaagent/lettuce-5.0-javaagent.gradle
  86. 1 1
      instrumentation/lettuce/lettuce-5.1/javaagent/lettuce-5.1-javaagent.gradle
  87. 7 1
      instrumentation/lettuce/lettuce-common/javaagent/lettuce-common-javaagent.gradle
  88. 4 0
      instrumentation/methods/javaagent/methods-javaagent.gradle
  89. 7 0
      instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java
  90. 0 9
      instrumentation/methods/javaagent/src/test/groovy/MethodTest.groovy
  91. 1 1
      instrumentation/mongo/mongo-async-3.3/javaagent/mongo-async-3.3-javaagent.gradle
  92. 14 2
      instrumentation/mongo/mongo-common/javaagent/mongo-common-javaagent.gradle
  93. 2 1
      instrumentation/okhttp/okhttp-3.0/javaagent/src/test/groovy/OkHttp3AsyncTest.groovy
  94. 5 1
      instrumentation/opentelemetry-annotations-1.0/javaagent/opentelemetry-annotations-1.0-javaagent.gradle
  95. 0 9
      instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy
  96. 2 2
      instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java
  97. 9 1
      instrumentation/opentelemetry-api-1.0/javaagent/opentelemetry-api-1.0-javaagent.gradle
  98. 110 152
      instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/ContextBridgeTest.groovy
  99. 3 3
      instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/ContextTest.groovy
  100. 25 23
      instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/MeterTest.groovy

+ 20 - 0
.github/scripts/deadlock-detector.sh

@@ -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 &

+ 23 - 13
.github/workflows/pr.yaml

@@ -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

+ 4 - 0
CONTRIBUTING.md

@@ -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)

+ 0 - 4
buildSrc/build.gradle

@@ -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"
-    }
   }
 }
 

+ 0 - 61
buildSrc/src/main/java/io/opentelemetry/instrumentation/gradle/AutoInstrumentationPlugin.java

@@ -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");
-    }
-  }
-}

+ 1 - 2
docs/contributing/javaagent-jar-components.md

@@ -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

+ 38 - 0
docs/contributing/javaagent-test-infra.md

@@ -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`.

+ 33 - 5
docs/contributing/writing-instrumentation.md

@@ -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

+ 9 - 14
docs/safety-mechanisms.md

@@ -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.
-
-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
+All instrumentation are written with instrumentation tests - these can be considered the unit tests
+of this project.
+
+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
 

+ 3 - 0
examples/distro/instrumentation/build.gradle

@@ -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"
 }

+ 21 - 19
gradle/dependencies.gradle

@@ -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}",

+ 71 - 15
gradle/instrumentation.gradle

@@ -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'
+  }
+}

+ 2 - 1
gradle/java.gradle

@@ -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"

+ 4 - 0
instrumentation/akka-actor-2.5/javaagent/akka-actor-2.5-javaagent.gradle

@@ -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'
 }

+ 0 - 4
instrumentation/akka-actor-2.5/javaagent/src/test/groovy/AkkaExecutorInstrumentationTest.groovy

@@ -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

+ 3 - 3
instrumentation/akka-actor-2.5/javaagent/src/test/scala/AkkaActors.scala

@@ -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")
 

+ 2 - 2
instrumentation/apache-camel-2.20/javaagent/apache-camel-2.20-javaagent.gradle

@@ -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"
 

+ 4 - 0
instrumentation/aws-lambda-1.0/javaagent/aws-lambda-1.0-javaagent.gradle

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

+ 2 - 1
instrumentation/aws-lambda-1.0/javaagent/src/test/groovy/io/opentelemetry/javaagent/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy

@@ -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> {

+ 12 - 0
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaSqsHandlerTest.groovy

@@ -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) {

+ 13 - 1
instrumentation/aws-lambda-1.0/library/src/test/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AwsLambdaTest.groovy

@@ -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> {

+ 0 - 1
instrumentation/aws-lambda-1.0/testing/aws-lambda-1.0-testing.gradle

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

+ 0 - 14
instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaRequestHandlerTest.groovy

@@ -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"

+ 0 - 14
instrumentation/aws-lambda-1.0/testing/src/main/groovy/io/opentelemetry/instrumentation/awslambda/v1_0/AbstractAwsLambdaSqsHandlerTest.groovy

@@ -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()

+ 1 - 1
instrumentation/aws-sdk/aws-sdk-1.11/javaagent/aws-sdk-1.11-javaagent.gradle

@@ -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'

+ 1 - 5
instrumentation/aws-sdk/aws-sdk-2.2/javaagent/aws-sdk-2.2-javaagent.gradle

@@ -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
 }

+ 9 - 1
instrumentation/cassandra/cassandra-3.0/javaagent/cassandra-3.0-javaagent.gradle

@@ -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.+'
 }

+ 8 - 0
instrumentation/classloaders/javaagent/classloaders-javaagent.gradle

@@ -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/")
 }

+ 2 - 3
instrumentation/classloaders/javaagent/src/test/groovy/ResourceInjectionTest.groovy

@@ -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:

+ 2 - 6
instrumentation/classloaders/javaagent/tomcat-testing/src/test/groovy/TomcatClassloadingTest.groovy

@@ -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")
   }
 }

+ 1 - 1
instrumentation/couchbase/couchbase-2.6/javaagent/couchbase-2.6-javaagent.gradle

@@ -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'

+ 11 - 5
instrumentation/dropwizard-testing/dropwizard-testing.gradle

@@ -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'

+ 2 - 2
instrumentation/elasticsearch/elasticsearch-rest-5.0/javaagent/elasticsearch-rest-5.0-javaagent.gradle

@@ -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'

+ 3 - 3
instrumentation/elasticsearch/elasticsearch-rest-6.4/javaagent/elasticsearch-rest-6.4-javaagent.gradle

@@ -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'

+ 3 - 3
instrumentation/elasticsearch/elasticsearch-transport-5.0/javaagent/elasticsearch-transport-5.0-javaagent.gradle

@@ -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'

+ 3 - 3
instrumentation/elasticsearch/elasticsearch-transport-5.3/javaagent/elasticsearch-transport-5.3-javaagent.gradle

@@ -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'

+ 3 - 3
instrumentation/elasticsearch/elasticsearch-transport-6.0/javaagent/elasticsearch-transport-6.0-javaagent.gradle

@@ -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'
 

+ 4 - 0
instrumentation/executors/javaagent/executors-javaagent.gradle

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

+ 0 - 8
instrumentation/executors/javaagent/src/test/groovy/ExecutorInstrumentationTest.groovy

@@ -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) }

+ 8 - 0
instrumentation/external-annotations/javaagent-unittests/external-annotations-javaagent-unittests.gradle

@@ -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')
+}

+ 0 - 0
instrumentation/external-annotations/javaagent/src/test/groovy/IncludeTest.groovy → instrumentation/external-annotations/javaagent-unittests/src/test/groovy/IncludeTest.groovy


+ 12 - 8
instrumentation/external-annotations/javaagent/external-annotations-javaagent.gradle

@@ -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]"
+})

+ 0 - 9
instrumentation/external-annotations/javaagent/src/test/groovy/ConfiguredTraceAnnotationsTest.groovy

@@ -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:

+ 0 - 9
instrumentation/external-annotations/javaagent/src/test/groovy/TracedMethodsExclusionTest.groovy

@@ -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

+ 2 - 1
instrumentation/finatra-2.9/javaagent/finatra-2.9-javaagent.gradle

@@ -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

+ 11 - 0
instrumentation/grizzly-2.0/javaagent/grizzly-2.0-javaagent.gradle

@@ -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"
+}

+ 0 - 4
instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyFilterchainServerTest.groovy

@@ -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
 

+ 0 - 4
instrumentation/grizzly-2.0/javaagent/src/test/groovy/GrizzlyTest.groovy

@@ -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()

+ 3 - 3
instrumentation/hibernate/hibernate-3.3/javaagent/hibernate-3.3-javaagent.gradle

@@ -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'

+ 3 - 3
instrumentation/hibernate/hibernate-4.0/javaagent/hibernate-4.0-javaagent.gradle

@@ -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"

+ 3 - 3
instrumentation/hibernate/hibernate-4.3/javaagent/hibernate-4.3-javaagent.gradle

@@ -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'

+ 10 - 0
instrumentation/hystrix-1.4/javaagent/hystrix-1.4-javaagent.gradle

@@ -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"
+}

+ 0 - 16
instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixObservableChainTest.groovy

@@ -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:

+ 0 - 19
instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixObservableTest.groovy

@@ -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
 

+ 0 - 18
instrumentation/hystrix-1.4/javaagent/src/test/groovy/HystrixTest.groovy

@@ -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) {

+ 3 - 0
instrumentation/instrumentation.gradle

@@ -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

+ 12 - 3
instrumentation/jaxrs-client/jaxrs-client-2.0/jaxrs-client-2.0-common/javaagent/jaxrs-client-2.0-common-javaagent.gradle

@@ -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'

+ 1 - 13
instrumentation/jaxrs/jaxrs-1.0/javaagent/src/test/groovy/JaxRsAnnotations1InstrumentationTest.groovy

@@ -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"() {

+ 2 - 1
instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-jersey-2.0/javaagent/jaxrs-2.0-jersey-2.0-javaagent.gradle

@@ -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:

+ 2 - 1
instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.0/javaagent/jaxrs-2.0-resteasy-3.0-javaagent.gradle

@@ -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') {

+ 2 - 1
instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-resteasy-3.1/javaagent/jaxrs-2.0-resteasy-3.1-javaagent.gradle

@@ -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') {

+ 0 - 12
instrumentation/jaxrs/jaxrs-2.0/jaxrs-2.0-testing/src/main/groovy/JaxRsAnnotationsInstrumentationTest.groovy

@@ -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"() {

+ 5 - 0
instrumentation/jdbc/javaagent-unittests/jdbc-javaagent-unittests.gradle

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

+ 0 - 0
instrumentation/jdbc/javaagent/src/test/groovy/JdbcConnectionUrlParserTest.groovy → instrumentation/jdbc/javaagent-unittests/src/test/groovy/JdbcConnectionUrlParserTest.groovy


+ 3 - 0
instrumentation/jdbc/javaagent/jdbc-javaagent.gradle

@@ -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"
+}

+ 0 - 8
instrumentation/jdbc/javaagent/src/test/groovy/JdbcInstrumentationTest.groovy

@@ -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"

+ 1 - 1
instrumentation/jedis/jedis-3.0/javaagent/jedis-3.0-javaagent.gradle

@@ -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.+'
 }

+ 8 - 4
instrumentation/jms-1.1/javaagent/src/jms2Test/groovy/SpringListenerJms2Test.groovy

@@ -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:

+ 4 - 4
instrumentation/jms-1.1/javaagent/src/jms2Test/groovy/SpringTemplateJms2Test.groovy

@@ -119,16 +119,16 @@ class SpringTemplateJms2Test extends AgentTestRunner {
     receivedMessage.text == "responded!"
     assertTraces(4) {
       trace(0, 1) {
-        producerSpan(it, 0, destinationType, destinationName)
+        consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
       }
       trace(1, 1) {
-        consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
+        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)")
       }
     }
 

+ 9 - 4
instrumentation/jms-1.1/javaagent/src/test/groovy/SpringListenerJms1Test.groovy

@@ -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:

+ 5 - 5
instrumentation/jms-1.1/javaagent/src/test/groovy/SpringTemplateJms1Test.groovy

@@ -98,17 +98,17 @@ class SpringTemplateJms1Test extends AgentTestRunner {
     receivedMessage.text == "responded!"
     assertTraces(4) {
       trace(0, 1) {
-        producerSpan(it, 0, destinationType, destinationName)
+        consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
       }
       trace(1, 1) {
-        consumerSpan(it, 0, destinationType, destinationName, msgId.get(), null, "receive")
+        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)")
       }
     }
 

+ 10 - 1
instrumentation/jsp-2.3/javaagent/jsp-2.3-javaagent.gradle

@@ -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=*'
+}

+ 0 - 9
instrumentation/jsp-2.3/javaagent/src/test/groovy/JspInstrumentationBasicTests.groovy

@@ -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

+ 0 - 9
instrumentation/jsp-2.3/javaagent/src/test/groovy/JspInstrumentationForwardTests.groovy

@@ -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

+ 16 - 0
instrumentation/kafka-clients-0.11/javaagent/kafka-clients-0.11-javaagent.gradle

@@ -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"
+})

+ 3 - 4
instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientBaseTest.groovy

@@ -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()

+ 0 - 15
instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientPropagationDisabledTest.groovy

@@ -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:

+ 0 - 9
instrumentation/kafka-clients-0.11/javaagent/src/test/groovy/KafkaClientPropagationEnabledTest.groovy

@@ -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:

+ 6 - 1
instrumentation/kafka-streams-0.11/javaagent/kafka-streams-0.11-javaagent.gradle

@@ -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"
+}

+ 0 - 9
instrumentation/kafka-streams-0.11/javaagent/src/test/groovy/KafkaStreamsTest.groovy

@@ -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"

+ 9 - 0
instrumentation/kotlinx-coroutines/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/kotlinxcoroutines/KotlinCoroutinesInstrumentationModule.java

@@ -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());

+ 5 - 3
instrumentation/kotlinx-coroutines/javaagent/src/test/kotlin/KotlinCoroutineTests.kt

@@ -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)

+ 6 - 0
instrumentation/kubernetes-client-7.0/javaagent-unittests/kubernetes-client-7.0-javaagent-unittests.gradle

@@ -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'
+}

+ 0 - 0
instrumentation/kubernetes-client-7.0/javaagent/src/test/groovy/KubernetesRequestUtilsTest.groovy → instrumentation/kubernetes-client-7.0/javaagent-unittests/src/test/groovy/KubernetesRequestUtilsTest.groovy


+ 1 - 1
instrumentation/lettuce/lettuce-5.0/javaagent/lettuce-5.0-javaagent.gradle

@@ -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')
 }

+ 1 - 1
instrumentation/lettuce/lettuce-5.1/javaagent/lettuce-5.1-javaagent.gradle

@@ -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.+'
 }

+ 7 - 1
instrumentation/lettuce/lettuce-common/javaagent/lettuce-common-javaagent.gradle

@@ -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"

+ 4 - 0
instrumentation/methods/javaagent/methods-javaagent.gradle

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

+ 7 - 0
instrumentation/methods/javaagent/src/main/java/io/opentelemetry/javaagent/instrumentation/methods/MethodInstrumentationModule.java

@@ -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;

+ 0 - 9
instrumentation/methods/javaagent/src/test/groovy/MethodTest.groovy

@@ -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

+ 1 - 1
instrumentation/mongo/mongo-async-3.3/javaagent/mongo-async-3.3-javaagent.gradle

@@ -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')
 }

+ 14 - 2
instrumentation/mongo/mongo-common/javaagent/mongo-common-javaagent.gradle

@@ -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'
 }

+ 2 - 1
instrumentation/okhttp/okhttp-3.0/javaagent/src/test/groovy/OkHttp3AsyncTest.groovy

@@ -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()
     }

+ 5 - 1
instrumentation/opentelemetry-annotations-1.0/javaagent/opentelemetry-annotations-1.0-javaagent.gradle

@@ -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]"
 }

+ 0 - 9
instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/groovy/WithSpanInstrumentationTest.groovy

@@ -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:

+ 2 - 2
instrumentation/opentelemetry-annotations-1.0/javaagent/src/test/java/io/opentelemetry/test/annotation/TracedWithSpan.java

@@ -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 {
 

+ 9 - 1
instrumentation/opentelemetry-api-1.0/javaagent/opentelemetry-api-1.0-javaagent.gradle

@@ -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]'
 }

+ 110 - 152
instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/ContextBridgeTest.groovy

@@ -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"
-        }
-      }
+  def "agent propagates application's context"() {
+    when:
+    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:
+    captured.get() == "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 "application propagates agent's context"() {
     when:
-    def applicationTracer = OpenTelemetry.getGlobalTracer("test")
-    def agentTracer = io.opentelemetry.api.OpenTelemetry.getGlobalTracer("test")
+    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 {
+          Span.current().setAttribute("dog", "no")
+          context.makeCurrent().withCloseable {
+            Span.current().setAttribute("cat", "yes")
+          }
+        }
+      }
+    }.run()
 
     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
+    assertTraces(1) {
+      trace(0, 1) {
+        span(0) {
+          name "test"
+          hasNoParent()
+          attributes {
+            "cat" "yes"
+          }
         }
       }
     }
   }
 
-  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")
-      }
+  def "agent propagates application's span"() {
+    when:
+    def tracer = OpenTelemetry.getGlobalTracer("test")
 
-      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")
-        }
+    def testSpan = tracer.spanBuilder("test").startSpan()
+    testSpan.makeCurrent().withCloseable {
+      Executors.newSingleThreadExecutor().submit({
+        Span.current().setAttribute("cat", "yes")
+      }).get()
+    }
+    testSpan.end()
 
-        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")
+    then:
+    assertTraces(1) {
+      trace(0, 1) {
+        span(0) {
+          name "test"
+          hasNoParent()
+          attributes {
+            "cat" "yes"
           }
         }
       }
     }
   }
 
-  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 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")
           }
         }
-        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 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))
-        }
+    }.run()
 
-        agentValue.get() == null
-        applicationValue.get() == null
-
-        def ctx = Context.current()
-        // Simulate another thread by remounting root
-        Context.root().makeCurrent().withCloseable {
-          io.opentelemetry.context.Context.root().makeCurrent().withCloseable {
-            ctx.wrap(runnable).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"
 }

+ 3 - 3
instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/ContextTest.groovy

@@ -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 {

+ 25 - 23
instrumentation/opentelemetry-api-1.0/javaagent/src/test/groovy/MeterTest.groovy

@@ -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 changed in this diff