Helper Injection test
ADD
dd-java-agent/tooling/src/test/groovy/dd/test/HelperInjectionTest.groovy
+package dd.test
+
+import static dd.test.TestUtils.createJarWithClasses
+
+import java.lang.reflect.Method
+import net.bytebuddy.agent.ByteBuddyAgent
+import net.bytebuddy.agent.builder.AgentBuilder
+import spock.lang.Specification
+
+import static net.bytebuddy.matcher.ElementMatchers.*
+
+class HelperInjectionTest extends Specification {
+ def setupSpec() {
+ AgentBuilder builder =
+ new AgentBuilder.Default()
+ .disableClassFormatChanges()
+ .with(AgentBuilder.RedefinitionStrategy.RETRANSFORMATION)
+ .ignore(nameStartsWith("dd.inst"))
+
+ builder = new TestInstrumentation().instrument(builder)
+
+ builder.installOn(ByteBuddyAgent.install())
+ }
+
+ def "helpers injected to non-delegating classloader"() {
+ setup:
+ URL[] classpath = [createJarWithClasses(TestInstrumentation.ClassToInstrument)]
+ URLClassLoader classloader = new URLClassLoader(classpath, (ClassLoader)null)
+
+ when:
+ classloader.loadClass(TestInstrumentation.HelperClass.getName())
+ then:
+ thrown ClassNotFoundException
+
+ when:
+ Class<?> instrumentedClass = classloader.loadClass(TestInstrumentation.ClassToInstrument.getName())
+ Method instrumentedMethod = instrumentedClass.getMethod("isInstrumented")
+ then:
+ instrumentedMethod.invoke(null)
+
+ when:
+ classloader.loadClass(TestInstrumentation.HelperClass.getName())
+ then:
+ noExceptionThrown()
+
+ cleanup:
+ classloader?.close()
+ }
+}

ADD
dd-java-agent/tooling/src/test/groovy/dd/test/TestInstrumentation.java
+package dd.test;
+
+import static net.bytebuddy.matcher.ElementMatchers.*;
+
+import dd.trace.DDAdvice;
+import dd.trace.HelperInjector;
+import dd.trace.Instrumenter;
+import net.bytebuddy.agent.builder.AgentBuilder;
+import net.bytebuddy.asm.Advice;
+
+public class TestInstrumentation implements Instrumenter {
+ @Override
+ public AgentBuilder instrument(AgentBuilder agentBuilder) {
+ return agentBuilder
+ .type(named(TestInstrumentation.class.getName() + "$ClassToInstrument"))
+ .transform(
+ DDAdvice.create()
+ .advice(
+ isMethod().and(isPublic()).and(named("isInstrumented")),
+ AdviceClass.class.getName()))
+ .asDecorator();
+ }
+
+ public static class ClassToInstrument {
+ public static boolean isInstrumented() {
+ return false;
+ }
+ }
+
+ public static class AdviceClass {
+ @Advice.OnMethodExit(suppress = Throwable.class)
+ public static void enterAdvice(@Advice.Return(readOnly = false) Boolean returnValue) {
+ returnValue = HelperClass.returnTrue();
+ }
+ }
+
+ public static class HelperClass {
+ public static boolean returnTrue() {
+ return true;
+ }
+ }
+}

Helper Injection test