diff --git a/internal-api/internal-api-9/build.gradle.kts b/internal-api/internal-api-9/build.gradle.kts index 47ede220d8b..bd9e9fbf3d1 100644 --- a/internal-api/internal-api-9/build.gradle.kts +++ b/internal-api/internal-api-9/build.gradle.kts @@ -34,6 +34,13 @@ listOf(JavaCompile::class.java, GroovyCompile::class.java).forEach { compileTask extra["minimumBranchCoverage"] = 0.8 extra["minimumInstructionCoverage"] = 0.8 +// Remaining uncovered code is JVM-specific fallbacks (ProcessHandle failures, IBM J9 frame mapping) +// that cannot be reached on the test JVMs. +extra["excludedClassesCoverage"] = listOf( + "datadog.trace.util.JDK9ExecutableSupplier", + "datadog.trace.util.JDK9PidSupplier", + "datadog.trace.util.stacktrace.JDK9StackWalker", +) dependencies { api(project(":internal-api")) diff --git a/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ExecutableSupplierTest.java b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ExecutableSupplierTest.java new file mode 100644 index 00000000000..888f5c9227c --- /dev/null +++ b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ExecutableSupplierTest.java @@ -0,0 +1,15 @@ +package datadog.trace.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class JDK9ExecutableSupplierTest { + + @Test + void returnsCurrentProcessExecutable() { + String expected = ProcessHandle.current().info().command().orElse(null); + + assertEquals(expected, new JDK9ExecutableSupplier().get()); + } +} diff --git a/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ModuleAccessTest.java b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ModuleAccessTest.java new file mode 100644 index 00000000000..acdcce55436 --- /dev/null +++ b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9ModuleAccessTest.java @@ -0,0 +1,80 @@ +package datadog.trace.util; + +import static datadog.trace.util.JDK9ModuleAccess.addModuleReads; +import static datadog.trace.util.JDK9ModuleAccess.canRead; +import static datadog.trace.util.JDK9ModuleAccess.exportModuleToUnnamedModule; +import static datadog.trace.util.JDK9ModuleAccess.getUnnamedModule; +import static java.util.Collections.singleton; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.instrument.Instrumentation; +import java.net.URL; +import java.net.URLClassLoader; +import net.bytebuddy.agent.ByteBuddyAgent; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +class JDK9ModuleAccessTest { + + private static Instrumentation inst; + + @BeforeAll + static void installAgent() { + inst = ByteBuddyAgent.install(); + } + + @Test + void getUnnamedModuleReturnsClassLoaderUnnamedModule() { + ClassLoader cl = newClassLoader(); + + assertSame(cl.getUnnamedModule(), getUnnamedModule(cl)); + } + + @Test + void canReadReflectsModuleReadability() { + Module unnamed = newClassLoader().getUnnamedModule(); + Module javaBase = Object.class.getModule(); + + // unnamed modules read every module, java.base reads no unnamed module + assertTrue(canRead(unnamed, javaBase)); + assertFalse(canRead(javaBase, unnamed)); + } + + @Test + void addModuleReadsMakesModuleReadable() { + Module javaSql = java.sql.Driver.class.getModule(); + Module unnamed = newClassLoader().getUnnamedModule(); + assertFalse(javaSql.canRead(unnamed)); + + addModuleReads(inst, javaSql, singleton(unnamed)); + + assertTrue(javaSql.canRead(unnamed)); + } + + @Test + void exportModuleToUnnamedModuleExportsPackages() { + ClassLoader cl = newClassLoader(); + Module javaBase = Object.class.getModule(); + assertFalse(javaBase.isExported("jdk.internal.misc", cl.getUnnamedModule())); + + exportModuleToUnnamedModule(inst, "java.base", new String[] {"jdk.internal.misc"}, cl); + + assertTrue(javaBase.isExported("jdk.internal.misc", cl.getUnnamedModule())); + } + + @Test + void exportModuleToUnnamedModuleIgnoresUnknownModule() { + ClassLoader cl = newClassLoader(); + + assertDoesNotThrow( + () -> exportModuleToUnnamedModule(inst, "does.not.exist", new String[] {"some.pkg"}, cl)); + } + + /** A fresh class loader, so module changes don't leak to other tests. */ + private static ClassLoader newClassLoader() { + return new URLClassLoader(new URL[0], null); + } +} diff --git a/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9PidSupplierTest.java b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9PidSupplierTest.java new file mode 100644 index 00000000000..a56b52e7eed --- /dev/null +++ b/internal-api/internal-api-9/src/test/java/datadog/trace/util/JDK9PidSupplierTest.java @@ -0,0 +1,13 @@ +package datadog.trace.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +class JDK9PidSupplierTest { + + @Test + void returnsCurrentProcessPid() { + assertEquals(Long.toString(ProcessHandle.current().pid()), new JDK9PidSupplier().get()); + } +}