Spock classloading tests
DELETE
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/TestLoggerRewrite.groovy
-package datadog.trace.agent.integration
-
-import io.opentracing.util.GlobalTracer
-import java.lang.reflect.Field
-import spock.lang.Specification
-
-class TestLoggerRewrite extends Specification {
- def "java getLogger rewritten to safe logger"() {
- setup:
- Field logField = GlobalTracer.getDeclaredField("LOGGER")
- logField.setAccessible(true)
- Object logger = logField.get(null)
-
- expect:
- !logger.getClass().getName().startsWith("java.util.logging")
-
- cleanup:
- logField?.setAccessible(false)
- }
-}

ADD
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/classloading/ClassLoadingTest.groovy
+package datadog.trace.agent.integration.classloading
+
+import datadog.trace.agent.test.IntegrationTestUtils
+
+import static datadog.trace.agent.test.IntegrationTestUtils.createJarWithClasses
+
+import datadog.trace.api.Trace
+import spock.lang.Specification
+
+
+class ClassLoadingTest extends Specification {
+
+ /** Assert that we can instrument classloaders which cannot resolve agent advice classes. */
+ def "instrument classloader without agent classes" () {
+ setup:
+ final URL[] classpath = [createJarWithClasses(ClassToInstrument, Trace)]
+ final URLClassLoader loader = new URLClassLoader(classpath, (ClassLoader)null)
+
+ when:
+ loader.loadClass("datadog.agent.TracingAgent")
+ then:
+ thrown ClassNotFoundException
+
+ when:
+ final Class<?> instrumentedClass = loader.loadClass(ClassToInstrument.getName())
+ then:
+ instrumentedClass.getClassLoader() == loader
+ }
+
+ def "can find bootstrap resources"() {
+ expect:
+ IntegrationTestUtils.getAgentClassLoader().getResources('datadog/trace/api/Trace.class') != null
+ }
+}

ADD
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/classloading/ClassToInstrument.java
+package datadog.trace.agent.integration.classloading;
+
+import datadog.trace.api.Trace;
+
+class ClassToInstrument {
+ @Trace
+ public static void someMethod() {}
+}

ADD
dd-java-agent-ittests/src/test/groovy/datadog/trace/agent/integration/classloading/ShadowPackageRenamingTest.groovy
+package datadog.trace.agent.integration.classloading
+
+import com.google.common.collect.MapMaker
+import com.google.common.reflect.ClassPath
+import datadog.trace.agent.test.IntegrationTestUtils
+import io.opentracing.util.GlobalTracer
+import spock.lang.Specification
+
+import java.lang.reflect.Field
+
+
+class ShadowPackageRenamingTest extends Specification {
+ def "agent dependencies renamed"() {
+ setup:
+ final Class<?> ddClass =
+ IntegrationTestUtils.getAgentClassLoader()
+ .loadClass("datadog.trace.agent.tooling.AgentInstaller")
+ final String userGuava =
+ MapMaker.getProtectionDomain().getCodeSource().getLocation().getFile()
+ final String agentGuavaDep =
+ ddClass
+ .getClassLoader()
+ .loadClass("datadog.trace.agent.deps.google.common.collect.MapMaker")
+ .getProtectionDomain()
+ .getCodeSource()
+ .getLocation()
+ .getFile()
+ final String agentSource =
+ ddClass.getProtectionDomain().getCodeSource().getLocation().getFile()
+
+ expect:
+ agentSource.matches(".*/agent-tooling-and-instrumentation[^/]*.jar")
+ agentSource == agentGuavaDep
+ agentSource != userGuava
+ }
+
+ def "java getLogger rewritten to safe logger"() {
+ setup:
+ Field logField = GlobalTracer.getDeclaredField("LOGGER")
+ logField.setAccessible(true)
+ Object logger = logField.get(null)
+
+ expect:
+ !logger.getClass().getName().startsWith("java.util.logging")
+
+ cleanup:
+ logField?.setAccessible(false)
+ }
+
+ def "agent classes not visible"() {
+ when:
+ ClassLoader.getSystemClassLoader().loadClass("datadog.trace.agent.tooling.AgentInstaller")
+ then:
+ thrown ClassNotFoundException
+ }
+
+ def "agent jar contains no bootstrap classes"() {
+ setup:
+ final ClassPath agentClasspath = ClassPath.from(IntegrationTestUtils.getAgentClassLoader())
+
+ final ClassPath bootstrapClasspath = ClassPath.from(IntegrationTestUtils.getBootstrapResourceLocator())
+ final Set<String> bootstrapClasses = new HashSet<>()
+ for (ClassPath.ClassInfo info : bootstrapClasspath.getAllClasses()) {
+ bootstrapClasses.add(info.getName())
+ // make sure all bootstrap classes can be loaded from system
+ ClassLoader.getSystemClassLoader().loadClass(info.getName())
+ }
+
+ final List<ClassPath.ClassInfo> duplicateClassFile = new ArrayList<>()
+ for (ClassPath.ClassInfo classInfo : agentClasspath.getAllClasses()) {
+ if (bootstrapClasses.contains(classInfo.getName())) {
+ duplicateClassFile.add(classInfo)
+ }
+ }
+
+ expect:
+ duplicateClassFile.size() == 0
+ }
+}

DELETE
dd-java-agent-ittests/src/test/java/datadog/trace/agent/ClassLoaderTest.java
-package datadog.trace.agent;
-
-import static datadog.trace.agent.test.IntegrationTestUtils.createJarWithClasses;
-
-import datadog.trace.api.Trace;
-import java.net.URL;
-import java.net.URLClassLoader;
-import org.junit.Assert;
-import org.junit.Test;
-
-// TODO: move to spock
-public class ClassLoaderTest {
-
- /** Assert that we can instrument classloaders which cannot resolve agent advice classes. */
- @Test
- public void instrumentClassLoadersWithoutAgentClasses() throws Exception {
- final URL[] classpath = new URL[] {createJarWithClasses(ClassToInstrument.class, Trace.class)};
- final URLClassLoader loader = new URLClassLoader(classpath, null);
-
- try {
- loader.loadClass("datadog.agent.TracingAgent");
- Assert.fail("loader should not see agent classes.");
- } catch (final ClassNotFoundException cnfe) {
- // Good. loader can't see agent classes.
- }
-
- final Class<?> instrumentedClass = loader.loadClass(ClassToInstrument.class.getName());
- Assert.assertEquals(
- "Class must be loaded by loader.", loader, instrumentedClass.getClassLoader());
-
- loader.close();
- }
-
- public static class ClassToInstrument {
- @Trace
- public static void someMethod() {}
- }
-
- // TODO: Write test: assert our agent resource locator can locate resources from the bootstrap jar
-
- // TODO: Write test: ensure all classes are available on java 9 (vs the platform loader)
-}

DELETE
dd-java-agent-ittests/src/test/java/datadog/trace/agent/ShadowPackageRenamingTest.java
-package datadog.trace.agent;
-
-import com.google.common.collect.MapMaker;
-import datadog.trace.agent.test.IntegrationTestUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-// TODO: move to spock
-// TODO: merge with log rewrite test
-public class ShadowPackageRenamingTest {
-
- @Test
- public void agentDependenciesRenamed() throws Exception {
- final Class<?> ddClass =
- IntegrationTestUtils.getAgentClassLoader()
- .loadClass("datadog.trace.agent.tooling.AgentInstaller");
-
- final String userGuava =
- MapMaker.class.getProtectionDomain().getCodeSource().getLocation().getFile();
- final String agentGuavaDep =
- ddClass
- .getClassLoader()
- .loadClass("datadog.trace.agent.deps.google.common.collect.MapMaker")
- .getProtectionDomain()
- .getCodeSource()
- .getLocation()
- .getFile();
- final String agentSource =
- ddClass.getProtectionDomain().getCodeSource().getLocation().getFile();
-
- Assert.assertTrue(
- "AgentInstaller should reside in the tmp tooling jar: " + agentSource,
- agentSource.matches(".*/agent-tooling-and-instrumentation[^/]*.jar"));
- Assert.assertEquals("DD guava dep must be loaded from agent jar.", agentSource, agentGuavaDep);
- Assert.assertNotEquals(
- "User guava dep must not be loaded from agent jar.", agentSource, userGuava);
- }
-
- // TODO: Write test
- // for every class in bootstrap jar:
- // assert class not present in agent jar
-
- // TODO: Write test: assert agent classes not visible
-}

MODIFY
dd-java-agent-ittests/src/test/java/datadog/trace/agent/test/IntegrationTestUtils.java
dd-java-agent-ittests/src/test/java/datadog/trace/agent/test/IntegrationTestUtils.java
@@ -52,6 +52,18 @@ public class IntegrationTestUtils {
}
}
+ /** Returns the URL to the jar the agent appended to the bootstrap classpath * */
+ public static ClassLoader getBootstrapResourceLocator() throws Exception {
+ final ClassLoader agentClassLoader = getAgentClassLoader();
+ final Field field = agentClassLoader.getClass().getDeclaredField("bootstrapResourceLocator");
+ try {
+ field.setAccessible(true);
+ return (ClassLoader) field.get(agentClassLoader);
+ } finally {
+ field.setAccessible(false);
+ }
+ }
+
/**
* Create a temporary jar on the filesystem with the bytes of the given classes.
*

MODIFY
dd-java-agent/agent-bootstrap/agent-bootstrap.gradle
dd-java-agent/agent-bootstrap/agent-bootstrap.gradle
@@ -3,8 +3,6 @@ plugins {
id "com.github.johnrengelman.shadow"
}
-// TODO include: opentracing, dd-ot-impl, dd-api
-// Also: Move Patch Logger into this project
apply from: "${rootDir}/gradle/java.gradle"
dependencies {

MODIFY
dd-java-agent/instrumentation/instrumentation.gradle
dd-java-agent/instrumentation/instrumentation.gradle
@@ -21,14 +21,19 @@ dependencies {
configurations {
// exclude bootstrap dependencies from shadowJar
- runtime.exclude module: ':dd-java-agent:agent-bootstrap'
- runtime.exclude module: ':dd-trace-api'
runtime.exclude module: deps.opentracing
runtime.exclude module: deps.slf4j
runtime.exclude group: 'org.slf4j'
runtime.exclude group: 'io.opentracing'
}
+shadowJar {
+ dependencies {
+ exclude(project(':dd-java-agent:agent-bootstrap'))
+ exclude(project(':dd-trace-api'))
+ }
+}
+
jar {
classifier = 'unbundled'
}

Spock classloading tests