diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy deleted file mode 100644 index f1163a53ba2d..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G -import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling -import net.bytebuddy.description.type.TypeDescription -import org.objectweb.asm.Opcodes -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass -import static net.bytebuddy.matcher.ElementMatchers.named - -class ExtendsClassMatcherTest extends Specification { - @Shared - def typePool = - AgentTooling.poolStrategy() - .typePool(AgentTooling.locationStrategy().classFileLocator(this.class.classLoader, null), this.class.classLoader) - - @Unroll - def "test matcher #matcherClass.simpleName -> #type.simpleName"() { - expect: - extendsClass(matcher).matches(argument) == result - - where: - matcherClass | type | result - A | B | false - A | F | false - G | F | false - F | F | true - F | G | true - - matcher = named(matcherClass.name) - argument = typePool.describe(type.name).resolve() - } - - def "test traversal exceptions"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = extendsClass(named(Object.name)) - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.getModifiers() >> Opcodes.ACC_ABSTRACT - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } - 0 * _ - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy deleted file mode 100644 index f0ba1abb214f..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.groovy +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G -import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling -import net.bytebuddy.description.type.TypeDescription -import net.bytebuddy.description.type.TypeList -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface -import static net.bytebuddy.matcher.ElementMatchers.named - -class HasInterfaceMatcherTest extends Specification { - @Shared - def typePool = - AgentTooling.poolStrategy() - .typePool(AgentTooling.locationStrategy().classFileLocator(this.class.classLoader, null), this.class.classLoader) - - @Unroll - def "test matcher #matcherClass.simpleName -> #type.simpleName"() { - expect: - implementsInterface(matcher).matches(argument) == result - - where: - matcherClass | type | result - A | A | true - A | B | true - B | A | false - A | E | true - A | F | true - A | G | true - F | A | false - F | F | false - F | G | false - - matcher = named(matcherClass.name) - argument = typePool.describe(type.name).resolve() - } - - def "test traversal exceptions"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = implementsInterface(named(Object.name)) - def interfaces = Mock(TypeList.Generic) - def it = new ThrowOnFirstElement() - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.isInterface() >> true - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - 1 * type.getInterfaces() >> interfaces - 1 * interfaces.iterator() >> it - 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } - 0 * _ - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy deleted file mode 100644 index 3b3be8d36ebd..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.groovy +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.C -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.Trace -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.TracedClass -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.UntracedClass -import net.bytebuddy.description.method.MethodDescription -import spock.lang.Specification - -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperMethod -import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith -import static net.bytebuddy.matcher.ElementMatchers.none - -class HasSuperMethodMatcherTest extends Specification { - - def "test matcher #type.simpleName #method"() { - expect: - hasSuperMethod(isAnnotatedWith(Trace)).matches(argument) == result - - where: - type | method | result - A | "a" | false - B | "b" | true - C | "c" | false - F | "f" | true - G | "g" | false - TracedClass | "a" | true - UntracedClass | "a" | false - UntracedClass | "b" | true - - argument = new MethodDescription.ForLoadedMethod(type.getDeclaredMethod(method)) - } - - def "test constructor never matches"() { - setup: - def method = Mock(MethodDescription) - def matcher = hasSuperMethod(none()) - - when: - def result = matcher.matches(method) - - then: - !result - 1 * method.isConstructor() >> true - 0 * _ - } - - def "test traversal exceptions"() { - setup: - def method = Mock(MethodDescription) - def matcher = hasSuperMethod(none()) - def sigToken = new MethodDescription.ForLoadedMethod(A.getDeclaredMethod("a")).asSignatureToken() - - when: - def result = matcher.matches(method) - - then: - !result // default to false - 1 * method.isConstructor() >> false - 1 * method.asSignatureToken() >> sigToken - 1 * method.getDeclaringType() >> null - 0 * _ - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy deleted file mode 100644 index 21b4512509c0..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.groovy +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G -import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling -import net.bytebuddy.description.type.TypeDescription -import net.bytebuddy.description.type.TypeList -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface -import static net.bytebuddy.matcher.ElementMatchers.named - -class ImplementsInterfaceMatcherTest extends Specification { - @Shared - def typePool = - AgentTooling.poolStrategy() - .typePool(AgentTooling.locationStrategy().classFileLocator(this.class.classLoader, null), this.class.classLoader) - - @Unroll - def "test matcher #matcherClass.simpleName -> #type.simpleName"() { - expect: - implementsInterface(matcher).matches(argument) == result - - where: - matcherClass | type | result - A | A | true - A | B | true - B | A | false - A | E | true - A | F | true - A | G | true - F | A | false - F | F | false - F | G | false - - matcher = named(matcherClass.name) - argument = typePool.describe(type.name).resolve() - } - - def "test exception getting interfaces"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = implementsInterface(named(Object.name)) - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.isInterface() >> true - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - 1 * type.getInterfaces() >> { throw new Exception("getInterfaces exception") } - 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } - 0 * _ - } - - def "test traversal exceptions"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = implementsInterface(named(Object.name)) - def interfaces = Mock(TypeList.Generic) - def it = new ThrowOnFirstElement() - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.isInterface() >> true - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - 1 * type.getInterfaces() >> interfaces - 1 * interfaces.iterator() >> it - 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } - 0 * _ - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.groovy deleted file mode 100644 index 10493115c276..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.groovy +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - - -import io.opentelemetry.javaagent.tooling.bytebuddy.LoggingFailSafeMatcher -import net.bytebuddy.matcher.ElementMatcher -import spock.lang.Specification - -class LoggingFailSafeMatcherTest extends Specification { - - def mockMatcher = Mock(ElementMatcher) - - def "test matcher"() { - setup: - def matcher = new LoggingFailSafeMatcher<>(mockMatcher, "test") - - when: - def result = matcher.matches(new Object()) - - then: - 1 * mockMatcher.matches(_) >> match - result == match - - where: - match << [true, false] - } - - def "test matcher exception"() { - setup: - def matcher = new LoggingFailSafeMatcher<>(mockMatcher, "test") - - when: - def result = matcher.matches(new Object()) - - then: - 1 * mockMatcher.matches(_) >> { throw new Exception("matcher exception") } - 0 * _ - noExceptionThrown() - !result // default to false - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy deleted file mode 100644 index bc3e1d4b4e40..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.groovy +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F -import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G -import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling -import net.bytebuddy.description.type.TypeDescription -import net.bytebuddy.description.type.TypeList -import spock.lang.Shared -import spock.lang.Specification -import spock.lang.Unroll - -import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType -import static net.bytebuddy.matcher.ElementMatchers.named - -class SafeHasSuperTypeMatcherTest extends Specification { - @Shared - def typePool = - AgentTooling.poolStrategy() - .typePool(AgentTooling.locationStrategy().classFileLocator(this.class.classLoader, null), this.class.classLoader) - - @Unroll - def "test matcher #matcherClass.simpleName -> #type.simpleName"() { - expect: - hasSuperType(matcher).matches(argument) == result - - where: - matcherClass | type | result - A | A | true - A | B | true - B | A | false - A | E | true - A | F | true - B | G | true - F | A | false - F | F | true - F | G | true - - matcher = named(matcherClass.name) - argument = typePool.describe(type.name).resolve() - } - - def "test exception getting interfaces"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = hasSuperType(named(Object.name)) - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - 1 * type.getInterfaces() >> { throw new Exception("getInterfaces exception") } - 1 * type.getSuperClass() >> { throw new Exception("getSuperClass exception") } - 0 * _ - } - - def "test traversal exceptions"() { - setup: - def type = Mock(TypeDescription) - def typeGeneric = Mock(TypeDescription.Generic) - def matcher = hasSuperType(named(Object.name)) - def interfaces = Mock(TypeList.Generic) - def it = new ThrowOnFirstElement() - - when: - def result = matcher.matches(type) - - then: - !result // default to false - noExceptionThrown() - 1 * type.getInterfaces() >> interfaces - 1 * interfaces.iterator() >> it - 1 * type.asGenericType() >> typeGeneric - 1 * typeGeneric.asErasure() >> { throw new Exception("asErasure exception") } - } -} diff --git a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.groovy b/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.groovy deleted file mode 100644 index f9012bb8d4b2..000000000000 --- a/javaagent-tooling/src/test/groovy/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.groovy +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright The OpenTelemetry Authors - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.opentelemetry.javaagent.tooling.bytebuddy.matcher - -class ThrowOnFirstElement implements Iterator { - - int i = 0 - - @Override - boolean hasNext() { - return i++ < 1 - } - - @Override - Object next() { - throw new Exception("iteration exception") - } -} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.java new file mode 100644 index 000000000000..401fbaed4134 --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ExtendsClassMatcherTest.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.extendsClass; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.pool.TypePool; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.objectweb.asm.Opcodes; + +class ExtendsClassMatcherTest { + + private static TypePool typePool; + + @BeforeAll + static void setUp() { + typePool = + AgentTooling.poolStrategy() + .typePool( + AgentTooling.locationStrategy() + .classFileLocator(ExtendsClassMatcherTest.class.getClassLoader(), null), + ExtendsClassMatcherTest.class.getClassLoader()); + } + + @ParameterizedTest + @CsvSource({ + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, true" + }) + void testMatcher(String matcherClassName, String typeClassName, boolean expectedResult) { + TypeDescription argument = typePool.describe(typeClassName).resolve(); + + boolean result = extendsClass(named(matcherClassName)).matches(argument); + + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void testTraversalExceptions() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + + when(type.getModifiers()).thenReturn(Opcodes.ACC_ABSTRACT); + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + when(type.getSuperClass()).thenThrow(new RuntimeException("getSuperClass exception")); + + boolean result = extendsClass(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + // should not throw + extendsClass(named(Object.class.getName())).matches(type); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.java new file mode 100644 index 000000000000..872d041d71c5 --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasInterfaceMatcherTest.java @@ -0,0 +1,80 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling; +import java.util.Iterator; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.pool.TypePool; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +@SuppressWarnings({"unchecked", "rawtypes"}) +class HasInterfaceMatcherTest { + + private static TypePool typePool; + + @BeforeAll + static void setUp() { + typePool = + AgentTooling.poolStrategy() + .typePool( + AgentTooling.locationStrategy() + .classFileLocator(HasInterfaceMatcherTest.class.getClassLoader(), null), + HasInterfaceMatcherTest.class.getClassLoader()); + } + + @ParameterizedTest + @CsvSource({ + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, false" + }) + void testMatcher(String matcherClassName, String typeClassName, boolean expectedResult) { + TypeDescription argument = typePool.describe(typeClassName).resolve(); + + boolean result = implementsInterface(named(matcherClassName)).matches(argument); + + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void testTraversalExceptions() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + TypeList.Generic interfaces = mock(TypeList.Generic.class); + Iterator iterator = new ThrowOnFirstElement(); + + when(type.isInterface()).thenReturn(true); + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + when(type.getInterfaces()).thenReturn(interfaces); + when(interfaces.iterator()).thenReturn(iterator); + when(type.getSuperClass()).thenThrow(new RuntimeException("getSuperClass exception")); + + boolean result = implementsInterface(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + assertThatCode(() -> implementsInterface(named(Object.class.getName())).matches(type)) + .doesNotThrowAnyException(); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.java new file mode 100644 index 000000000000..8e243e3b5b5a --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/HasSuperMethodMatcherTest.java @@ -0,0 +1,69 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperMethod; +import static net.bytebuddy.matcher.ElementMatchers.isAnnotatedWith; +import static net.bytebuddy.matcher.ElementMatchers.none; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A; +import io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.Trace; +import net.bytebuddy.description.method.MethodDescription; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class HasSuperMethodMatcherTest { + + @ParameterizedTest + @CsvSource({ + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, a, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, b, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.C, c, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, f, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, g, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.TracedClass, a, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.UntracedClass, a, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.UntracedClass, b, true" + }) + void testMatcher(String className, String methodName, boolean expectedResult) throws Exception { + Class clazz = Class.forName(className); + MethodDescription argument = + new MethodDescription.ForLoadedMethod(clazz.getDeclaredMethod(methodName)); + + boolean result = hasSuperMethod(isAnnotatedWith(Trace.class)).matches(argument); + + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void testConstructorNeverMatches() { + MethodDescription method = mock(MethodDescription.class); + when(method.isConstructor()).thenReturn(true); + + boolean result = hasSuperMethod(none()).matches(method); + + assertThat(result).isFalse(); + } + + @Test + void testTraversalExceptions() throws Exception { + MethodDescription method = mock(MethodDescription.class); + MethodDescription.SignatureToken sigToken = + new MethodDescription.ForLoadedMethod(A.class.getDeclaredMethod("a")).asSignatureToken(); + + when(method.isConstructor()).thenReturn(false); + when(method.asSignatureToken()).thenReturn(sigToken); + when(method.getDeclaringType()).thenReturn(null); + + boolean result = hasSuperMethod(none()).matches(method); + + assertThat(result).isFalse(); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.java new file mode 100644 index 000000000000..84bb286197e4 --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ImplementsInterfaceMatcherTest.java @@ -0,0 +1,98 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.implementsInterface; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling; +import java.util.Iterator; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.pool.TypePool; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class ImplementsInterfaceMatcherTest { + + private static TypePool typePool; + + @BeforeAll + static void setUp() { + typePool = + AgentTooling.poolStrategy() + .typePool( + AgentTooling.locationStrategy() + .classFileLocator(ImplementsInterfaceMatcherTest.class.getClassLoader(), null), + ImplementsInterfaceMatcherTest.class.getClassLoader()); + } + + @ParameterizedTest + @CsvSource({ + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, false" + }) + void testMatcher(String matcherClassName, String typeClassName, boolean expectedResult) { + TypeDescription argument = typePool.describe(typeClassName).resolve(); + + boolean result = implementsInterface(named(matcherClassName)).matches(argument); + + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void testExceptionGettingInterfaces() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + + when(type.isInterface()).thenReturn(true); + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + when(type.getInterfaces()).thenThrow(new RuntimeException("getInterfaces exception")); + when(type.getSuperClass()).thenThrow(new RuntimeException("getSuperClass exception")); + + boolean result = implementsInterface(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + assertThatCode(() -> implementsInterface(named(Object.class.getName())).matches(type)) + .doesNotThrowAnyException(); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Test + void testTraversalExceptions() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + TypeList.Generic interfaces = mock(TypeList.Generic.class); + Iterator iterator = new ThrowOnFirstElement(); + + when(type.isInterface()).thenReturn(true); + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + when(type.getInterfaces()).thenReturn(interfaces); + when(interfaces.iterator()).thenReturn(iterator); + when(type.getSuperClass()).thenThrow(new RuntimeException("getSuperClass exception")); + + boolean result = implementsInterface(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + assertThatCode(() -> implementsInterface(named(Object.class.getName())).matches(type)) + .doesNotThrowAnyException(); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.java new file mode 100644 index 000000000000..e09ff4883f2b --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/LoggingFailSafeMatcherTest.java @@ -0,0 +1,46 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.bytebuddy.LoggingFailSafeMatcher; +import net.bytebuddy.matcher.ElementMatcher; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +@SuppressWarnings({"unchecked", "rawtypes"}) +class LoggingFailSafeMatcherTest { + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void testMatcher(boolean match) { + ElementMatcher mockMatcher = mock(ElementMatcher.class); + when(mockMatcher.matches(any())).thenReturn(match); + + LoggingFailSafeMatcher matcher = new LoggingFailSafeMatcher<>(mockMatcher, "test"); + + boolean result = matcher.matches(new Object()); + + assertThat(result).isEqualTo(match); + } + + @Test + void testMatcherException() { + ElementMatcher mockMatcher = mock(ElementMatcher.class); + when(mockMatcher.matches(any())).thenThrow(new RuntimeException("matcher exception")); + + LoggingFailSafeMatcher matcher = new LoggingFailSafeMatcher<>(mockMatcher, "test"); + + assertThatCode(() -> matcher.matches(new Object())).doesNotThrowAnyException(); + assertThat(matcher.matches(new Object())).isFalse(); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.java new file mode 100644 index 000000000000..000c011b17cf --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/SafeHasSuperTypeMatcherTest.java @@ -0,0 +1,95 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import static io.opentelemetry.javaagent.extension.matcher.AgentElementMatchers.hasSuperType; +import static net.bytebuddy.matcher.ElementMatchers.named; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import io.opentelemetry.javaagent.tooling.muzzle.AgentTooling; +import java.util.Iterator; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.description.type.TypeList; +import net.bytebuddy.pool.TypePool; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +@SuppressWarnings({"unchecked", "rawtypes"}) +class SafeHasSuperTypeMatcherTest { + + private static TypePool typePool; + + @BeforeAll + static void setUp() { + typePool = + AgentTooling.poolStrategy() + .typePool( + AgentTooling.locationStrategy() + .classFileLocator(SafeHasSuperTypeMatcherTest.class.getClassLoader(), null), + SafeHasSuperTypeMatcherTest.class.getClassLoader()); + } + + @ParameterizedTest + @CsvSource({ + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.E, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.B, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.A, false", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, true", + "io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.F, io.opentelemetry.javaagent.tooling.bytebuddy.matcher.testclasses.G, true" + }) + void testMatcher(String matcherClassName, String typeClassName, boolean expectedResult) { + TypeDescription argument = typePool.describe(typeClassName).resolve(); + + boolean result = hasSuperType(named(matcherClassName)).matches(argument); + + assertThat(result).isEqualTo(expectedResult); + } + + @Test + void testExceptionGettingInterfaces() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + when(type.getInterfaces()).thenThrow(new RuntimeException("getInterfaces exception")); + when(type.getSuperClass()).thenThrow(new RuntimeException("getSuperClass exception")); + + boolean result = hasSuperType(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + assertThatCode(() -> hasSuperType(named(Object.class.getName())).matches(type)) + .doesNotThrowAnyException(); + } + + @Test + void testTraversalExceptions() { + TypeDescription type = mock(TypeDescription.class); + TypeDescription.Generic typeGeneric = mock(TypeDescription.Generic.class); + TypeList.Generic interfaces = mock(TypeList.Generic.class); + Iterator iterator = new ThrowOnFirstElement(); + + when(type.getInterfaces()).thenReturn(interfaces); + when(interfaces.iterator()).thenReturn(iterator); + when(type.asGenericType()).thenReturn(typeGeneric); + when(typeGeneric.asErasure()).thenThrow(new RuntimeException("asErasure exception")); + + boolean result = hasSuperType(named(Object.class.getName())).matches(type); + + assertThat(result).isFalse(); + assertThatCode(() -> hasSuperType(named(Object.class.getName())).matches(type)) + .doesNotThrowAnyException(); + } +} diff --git a/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.java b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.java new file mode 100644 index 000000000000..c630b7816b0d --- /dev/null +++ b/javaagent-tooling/src/test/java/io/opentelemetry/javaagent/tooling/bytebuddy/matcher/ThrowOnFirstElement.java @@ -0,0 +1,22 @@ +/* + * Copyright The OpenTelemetry Authors + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.opentelemetry.javaagent.tooling.bytebuddy.matcher; + +import java.util.Iterator; + +class ThrowOnFirstElement implements Iterator { + private int current = 0; + + @Override + public boolean hasNext() { + return current++ < 1; + } + + @Override + public Object next() { + throw new RuntimeException("iteration exception"); + } +}