Skip to content

Commit ff44af8

Browse files
JonasKunzlaurit
andauthored
Added unit test for DefineClassInstrumentation (#12483)
Co-authored-by: Lauri Tulmin <[email protected]>
1 parent d3e1a2c commit ff44af8

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.internal.classloader;
7+
8+
import static org.mockito.ArgumentMatchers.eq;
9+
import static org.mockito.ArgumentMatchers.same;
10+
import static org.mockito.Mockito.verify;
11+
12+
import io.opentelemetry.javaagent.bootstrap.DefineClassHelper;
13+
import java.io.ByteArrayOutputStream;
14+
import java.io.IOException;
15+
import java.io.InputStream;
16+
import java.security.ProtectionDomain;
17+
import org.apache.commons.compress.utils.IOUtils;
18+
import org.junit.jupiter.params.ParameterizedTest;
19+
import org.junit.jupiter.params.provider.ValueSource;
20+
import org.mockito.Mockito;
21+
22+
class DefineClassInstrumentationTest {
23+
24+
public static class DefiningClassLoader extends ClassLoader {
25+
26+
public DefiningClassLoader() {
27+
super(null);
28+
}
29+
30+
// Suppressing warnings to force testing of deprecated method
31+
@SuppressWarnings("deprecation")
32+
public Class<?> doDefineClass(byte[] b, int off, int len) {
33+
return defineClass(b, off, len);
34+
}
35+
36+
public Class<?> doDefineClass(String name, byte[] b, int off, int len) {
37+
return defineClass(name, b, off, len);
38+
}
39+
40+
public Class<?> doDefineClass(
41+
String name, byte[] b, int off, int len, ProtectionDomain protectionDomain) {
42+
return defineClass(name, b, off, len, protectionDomain);
43+
}
44+
}
45+
46+
@ParameterizedTest
47+
@ValueSource(ints = {3, 4, 5})
48+
@SuppressWarnings("DirectInvocationOnMock")
49+
void ensureDefineClassInstrumented(int argCount) throws IOException {
50+
String className = Dummy.class.getName();
51+
String resource = className.replace('.', '/') + ".class";
52+
ByteArrayOutputStream byteCodeStream = new ByteArrayOutputStream();
53+
try (InputStream classfile = getClass().getResourceAsStream("/" + resource)) {
54+
IOUtils.copy(classfile, byteCodeStream, 1024);
55+
}
56+
byte[] bytecode = byteCodeStream.toByteArray();
57+
58+
DefiningClassLoader cl = new DefiningClassLoader();
59+
60+
DefineClassHelper.Handler mockHandler = Mockito.mock(DefineClassHelper.Handler.class);
61+
// We need to initialize mockHandler by invoking it early, otherwise this leads to problems
62+
mockHandler.beforeDefineClass(cl, className, bytecode, 0, bytecode.length);
63+
Mockito.reset(mockHandler);
64+
65+
DefineClassHelper.Handler originalHandler =
66+
DefineClassHelper.internalSetHandlerForTests(mockHandler);
67+
String expectedClassName;
68+
try {
69+
switch (argCount) {
70+
case 3:
71+
expectedClassName = null;
72+
cl.doDefineClass(bytecode, 0, bytecode.length);
73+
break;
74+
case 4:
75+
expectedClassName = className;
76+
cl.doDefineClass(className, bytecode, 0, bytecode.length);
77+
break;
78+
case 5:
79+
expectedClassName = className;
80+
cl.doDefineClass(className, bytecode, 0, bytecode.length, null);
81+
break;
82+
default:
83+
throw new IllegalStateException();
84+
}
85+
} finally {
86+
DefineClassHelper.internalSetHandlerForTests(originalHandler);
87+
}
88+
89+
verify(mockHandler)
90+
.beforeDefineClass(
91+
same(cl), eq(expectedClassName), eq(bytecode), eq(0), eq(bytecode.length));
92+
verify(mockHandler).afterDefineClass(eq(null));
93+
}
94+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* Copyright The OpenTelemetry Authors
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
package io.opentelemetry.javaagent.instrumentation.internal.classloader;
7+
8+
class Dummy {}

javaagent-bootstrap/src/main/java/io/opentelemetry/javaagent/bootstrap/DefineClassHelper.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,18 @@ public static void internalSetHandler(Handler handler) {
7070
DefineClassHelper.handler = handler;
7171
}
7272

73+
/**
74+
* Only for testing. In contrast to {@link #internalSetHandler(Handler)} allows replacing the
75+
* handler if it already has been set.
76+
*
77+
* @param handler the handler to set
78+
* @return the previously active handler
79+
*/
80+
public static Handler internalSetHandlerForTests(Handler handler) {
81+
Handler oldHandler = DefineClassHelper.handler;
82+
DefineClassHelper.handler = handler;
83+
return oldHandler;
84+
}
85+
7386
private DefineClassHelper() {}
7487
}

0 commit comments

Comments
 (0)