diff --git a/instrumentation/internal/internal-class-loader/javaagent-integration-tests/internal-class-loader-javaagent-integration-tests.gradle b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/internal-class-loader-javaagent-integration-tests.gradle new file mode 100644 index 0000000000..b924e04b93 --- /dev/null +++ b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/internal-class-loader-javaagent-integration-tests.gradle @@ -0,0 +1,9 @@ +ext.skipPublish = true + +apply from: "$rootDir/gradle/instrumentation.gradle" + +dependencies { + testImplementation group: "org.apache.commons", name: "commons-lang3", version: "3.12.0" + + testInstrumentation project(":instrumentation:internal:internal-class-loader:javaagent") +} diff --git a/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/main/java/instrumentation/TestInstrumentationModule.java b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/main/java/instrumentation/TestInstrumentationModule.java new file mode 100644 index 0000000000..bc3c132903 --- /dev/null +++ b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/main/java/instrumentation/TestInstrumentationModule.java @@ -0,0 +1,55 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package instrumentation; + +import static io.opentelemetry.javaagent.extension.matcher.ClassLoaderMatcher.hasClassesNamed; +import static java.util.Collections.singletonList; +import static net.bytebuddy.matcher.ElementMatchers.named; + +import com.google.auto.service.AutoService; +import io.opentelemetry.javaagent.extension.instrumentation.InstrumentationModule; +import io.opentelemetry.javaagent.extension.instrumentation.TypeInstrumentation; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; + +@AutoService(InstrumentationModule.class) +public class TestInstrumentationModule extends InstrumentationModule { + public TestInstrumentationModule() { + super("test-instrumentation"); + } + + @Override + public List typeInstrumentations() { + return singletonList(new TestTypeInstrumentation()); + } + + @Override + public String[] helperResourceNames() { + return new String[] {"test-resources/test-resource.txt"}; + } + + public static class TestTypeInstrumentation implements TypeInstrumentation { + @Override + public ElementMatcher classLoaderOptimization() { + return hasClassesNamed("org.apache.commons.lang3.SystemUtils"); + } + + @Override + public ElementMatcher typeMatcher() { + return named("org.apache.commons.lang3.SystemUtils"); + } + + @Override + public Map, String> transformers() { + // Nothing to transform, this type instrumentation is only used for injecting resources. + return Collections.emptyMap(); + } + } +} diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/test/resources/test-resources/test-resource.txt b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/main/resources/test-resources/test-resource.txt similarity index 100% rename from instrumentation/internal/internal-class-loader/javaagent/src/test/resources/test-resources/test-resource.txt rename to instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/main/resources/test-resources/test-resource.txt diff --git a/instrumentation/internal/internal-class-loader/javaagent/src/test/groovy/ResourceInjectionTest.groovy b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/test/groovy/ResourceInjectionTest.groovy similarity index 77% rename from instrumentation/internal/internal-class-loader/javaagent/src/test/groovy/ResourceInjectionTest.groovy rename to instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/test/groovy/ResourceInjectionTest.groovy index 1d1dfbf80b..b6ea22f106 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/src/test/groovy/ResourceInjectionTest.groovy +++ b/instrumentation/internal/internal-class-loader/javaagent-integration-tests/src/test/groovy/ResourceInjectionTest.groovy @@ -6,16 +6,18 @@ import static io.opentelemetry.instrumentation.test.utils.GcUtils.awaitGc import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification -import io.opentelemetry.javaagent.testing.common.HelperInjectorAccess + import java.lang.ref.WeakReference import java.util.concurrent.atomic.AtomicReference +import org.apache.commons.lang3.SystemUtils class ResourceInjectionTest extends AgentInstrumentationSpecification { def "resources injected to non-delegating classloader"() { setup: String resourceName = 'test-resources/test-resource.txt' - AtomicReference emptyLoader = new AtomicReference<>(new URLClassLoader(new URL[0], (ClassLoader) null)) + URL[] urls = [ SystemUtils.getProtectionDomain().getCodeSource().getLocation() ] + AtomicReference emptyLoader = new AtomicReference<>(new URLClassLoader(urls, (ClassLoader) null)) when: def resourceUrls = emptyLoader.get().getResources(resourceName) @@ -23,9 +25,11 @@ class ResourceInjectionTest extends AgentInstrumentationSpecification { !resourceUrls.hasMoreElements() when: - URLClassLoader notInjectedLoader = new URLClassLoader(new URL[0], (ClassLoader) null) + URLClassLoader notInjectedLoader = new URLClassLoader(urls, (ClassLoader) null) + + // this triggers resource injection + emptyLoader.get().loadClass(SystemUtils.getName()) - HelperInjectorAccess.injectResources(emptyLoader.get(), resourceName) resourceUrls = emptyLoader.get().getResources(resourceName) then: diff --git a/instrumentation/internal/internal-class-loader/javaagent/internal-class-loader-javaagent.gradle b/instrumentation/internal/internal-class-loader/javaagent/internal-class-loader-javaagent.gradle index 09b9e57ca1..7e96eac0e6 100644 --- a/instrumentation/internal/internal-class-loader/javaagent/internal-class-loader-javaagent.gradle +++ b/instrumentation/internal/internal-class-loader/javaagent/internal-class-loader-javaagent.gradle @@ -19,11 +19,3 @@ dependencies { testImplementation group: 'org.eclipse.platform', name: 'org.eclipse.osgi', version: '3.13.200' testImplementation group: 'org.apache.felix', name: 'org.apache.felix.framework', version: '6.0.2' } - -// 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/") -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 65a12bf7b5..9bcd980cb2 100644 --- a/settings.gradle +++ b/settings.gradle @@ -86,6 +86,7 @@ include ':instrumentation:cassandra:cassandra-3.0:javaagent' include ':instrumentation:cassandra:cassandra-4.0:javaagent' include ':instrumentation:cdi-testing' include ':instrumentation:internal:internal-class-loader:javaagent' +include ':instrumentation:internal:internal-class-loader:javaagent-integration-tests' include ':instrumentation:internal:internal-eclipse-osgi-3.6:javaagent' include ':instrumentation:internal:internal-proxy:javaagent' include ':instrumentation:internal:internal-proxy:javaagent-unit-tests' diff --git a/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/HelperInjectorAccess.java b/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/HelperInjectorAccess.java deleted file mode 100644 index 18139c2b81..0000000000 --- a/testing-common/src/main/java/io/opentelemetry/javaagent/testing/common/HelperInjectorAccess.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.testing.common; - -import static java.lang.invoke.MethodType.methodType; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -public final class HelperInjectorAccess { - - private static final MethodHandle helperInjectorConstructor; - private static final MethodHandle transform; - - static { - try { - Class helperInjectorClass = - AgentClassLoaderAccess.loadClass("io.opentelemetry.javaagent.tooling.HelperInjector"); - MethodHandles.Lookup lookup = MethodHandles.lookup(); - helperInjectorConstructor = - lookup.findConstructor( - helperInjectorClass, methodType(void.class, String.class, List.class, List.class)); - transform = - lookup.unreflect( - Arrays.stream(helperInjectorClass.getDeclaredMethods()) - .filter(method -> method.getName().equals("transform")) - .findFirst() - .get()); - } catch (Throwable t) { - throw new Error("Could not access HelperInjector through reflection"); - } - } - - public static void injectResources(ClassLoader classLoader, String... resources) { - try { - Object injector = - helperInjectorConstructor.invoke( - "test", Collections.emptyList(), Arrays.asList(resources)); - transform.invoke(injector, null, null, classLoader, null); - } catch (Throwable t) { - throw new Error("Could not invoke helper injection through reflection."); - } - } - - private HelperInjectorAccess() {} -}