opentelemetry-java-instrume.../testing-common/integration-tests/src/test/groovy/AgentInstrumentationSpecifi...

155 lines
4.6 KiB
Groovy

/*
* Copyright The OpenTelemetry Authors
* SPDX-License-Identifier: Apache-2.0
*/
import com.google.common.reflect.ClassPath
import io.opentelemetry.instrumentation.test.AgentInstrumentationSpecification
import io.opentelemetry.instrumentation.test.utils.ClasspathUtils
import io.opentelemetry.javaagent.bootstrap.BootstrapPackagePrefixesHolder
import org.slf4j.LoggerFactory
import java.util.concurrent.TimeoutException
// this test is run using
// -Dotel.javaagent.exclude-classes=config.exclude.packagename.*,config.exclude.SomeClass,config.exclude.SomeClass$NestedClass
// (see integration-tests.gradle)
class AgentInstrumentationSpecificationTest extends AgentInstrumentationSpecification {
private static final ClassLoader BOOTSTRAP_CLASSLOADER = null
public static final List<String> BOOTSTRAP_PACKAGE_PREFIXES = BootstrapPackagePrefixesHolder.getBoostrapPackagePrefixes()
def "classpath setup"() {
setup:
final List<String> bootstrapClassesIncorrectlyLoaded = []
for (ClassPath.ClassInfo info : getTestClasspath().getAllClasses()) {
for (int i = 0; i < BOOTSTRAP_PACKAGE_PREFIXES.size(); ++i) {
if (info.getName().startsWith(BOOTSTRAP_PACKAGE_PREFIXES[i])) {
Class<?> bootstrapClass = Class.forName(info.getName())
def loader
try {
loader = bootstrapClass.getClassLoader()
} catch (NoClassDefFoundError e) {
// some classes in com.google.errorprone.annotations cause groovy to throw
// java.lang.NoClassDefFoundError: [Ljavax/lang/model/element/Modifier;
break
}
if (loader != BOOTSTRAP_CLASSLOADER) {
bootstrapClassesIncorrectlyLoaded.add(bootstrapClass)
}
break
}
}
}
expect:
bootstrapClassesIncorrectlyLoaded == []
}
def "waiting for child spans times out"() {
when:
runWithSpan("parent") {
waitForTraces(1)
}
then:
thrown(TimeoutException)
}
def "logging works"() {
when:
LoggerFactory.getLogger(AgentInstrumentationSpecificationTest).debug("hello")
then:
noExceptionThrown()
}
def "excluded classes are not instrumented"() {
when:
runWithSpan("parent") {
subject.getConstructor().newInstance().run()
}
then:
assertTraces(1) {
trace(0, spanName ? 2 : 1) {
span(0) {
name "parent"
}
if (spanName) {
span(1) {
name spanName
childOf span(0)
}
}
}
}
where:
subject | spanName
config.SomeClass | "SomeClass.run"
config.SomeClass.NestedClass | "NestedClass.run"
config.exclude.SomeClass | null
config.exclude.SomeClass.NestedClass | null
config.exclude.packagename.SomeClass | null
config.exclude.packagename.SomeClass.NestedClass | null
}
def "test unblocked by completed span"() {
setup:
runWithSpan("parent") {
runWithSpan("child") {}
}
expect:
assertTraces(1) {
trace(0, 2) {
span(0) {
name "parent"
hasNoParent()
}
span(1) {
name "child"
childOf span(0)
}
}
}
}
private static ClassPath getTestClasspath() {
ClassLoader testClassLoader = ClasspathUtils.getClassLoader()
if (!(testClassLoader instanceof URLClassLoader)) {
// java9's system loader does not extend URLClassLoader
// which breaks Guava ClassPath lookup
testClassLoader = buildJavaClassPathClassLoader()
}
try {
return ClassPath.from(testClassLoader)
} catch (IOException e) {
throw new IllegalStateException(e)
}
}
/**
* Parse JVM classpath and return ClassLoader containing all classpath entries. Inspired by Guava.
*/
private static ClassLoader buildJavaClassPathClassLoader() {
List<URL> urls = new ArrayList<>()
for (String entry : getClasspath()) {
try {
try {
urls.add(new File(entry).toURI().toURL())
} catch (SecurityException e) { // File.toURI checks to see if the file is a directory
urls.add(new URL("file", null, new File(entry).getAbsolutePath()))
}
} catch (MalformedURLException e) {
throw new IllegalStateException(e)
}
}
return new URLClassLoader(urls.toArray(new URL[0]), (ClassLoader) null)
}
private static String[] getClasspath() {
return System.getProperty("java.class.path").split(System.getProperty("path.separator"))
}
}