8239350: Add tests for JFR class redefinition events
Reviewed-by: mgronlun
This commit is contained in:
parent
f75f78ae3a
commit
b6c1b49c97
92
test/jdk/jdk/jfr/event/runtime/Bytes.java
Normal file
92
test/jdk/jdk/jfr/event/runtime/Bytes.java
Normal file
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Helper class for working with class files and byte arrays
|
||||
*/
|
||||
public final class Bytes {
|
||||
public final static byte[] WORLD = Bytes.asBytes("world");
|
||||
public final static byte[] EARTH = Bytes.asBytes("earth");
|
||||
|
||||
public static byte[] asBytes(String string) {
|
||||
byte[] result = new byte[string.length()];
|
||||
for (int i = 0; i < string.length(); i++) {
|
||||
result[i] = (byte)string.charAt(i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] classBytes(ClassLoader classLoader, String className) throws IOException {
|
||||
String classFileName = className.replace(".", "/") + ".class";
|
||||
try (InputStream is = classLoader.getResourceAsStream(classFileName)) {
|
||||
if (is == null) {
|
||||
throw new IOException("Could not find class file " + classFileName);
|
||||
}
|
||||
return is.readAllBytes();
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] classBytes(Class<?> clazz) throws IOException {
|
||||
return classBytes(clazz.getClassLoader(), clazz.getName());
|
||||
}
|
||||
|
||||
public static byte[] replaceAll(byte[] input, byte[] target, byte[] replacement) {
|
||||
List<Byte> result = new ArrayList<>();
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
if (hasTarget(input, i, target)) {
|
||||
for (int j = 0; j < replacement.length; j++) {
|
||||
result.add(replacement[j]);
|
||||
}
|
||||
i += target.length - 1;
|
||||
} else {
|
||||
result.add(input[i]);
|
||||
}
|
||||
}
|
||||
byte[] resultArray = new byte[result.size()];
|
||||
for (int i = 0; i < resultArray.length; i++) {
|
||||
resultArray[i] = result.get(i);
|
||||
}
|
||||
return resultArray;
|
||||
}
|
||||
|
||||
private static boolean hasTarget(byte[] input, int start, byte[] target) {
|
||||
for (int i = 0; i < target.length; i++) {
|
||||
if (start + i == input.length) {
|
||||
return false;
|
||||
}
|
||||
if (input[start + i] != target[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
34
test/jdk/jdk/jfr/event/runtime/RedefinableClass.java
Normal file
34
test/jdk/jdk/jfr/event/runtime/RedefinableClass.java
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
// Class used by redefinition events
|
||||
public class RedefinableClass {
|
||||
public static void sayHello() {
|
||||
System.out.println("hello, world!");
|
||||
System.out.println();
|
||||
}
|
||||
}
|
102
test/jdk/jdk/jfr/event/runtime/TestClassRedefinition.java
Normal file
102
test/jdk/jdk/jfr/event/runtime/TestClassRedefinition.java
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedClass;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
import jdk.test.lib.jfr.Events;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Tests ClassRedefinition event by redefining classes in a Java agent
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib /test/jdk
|
||||
* @modules java.instrument
|
||||
*
|
||||
* @build jdk.jfr.event.runtime.RedefinableClass
|
||||
* @build jdk.jfr.event.runtime.Bytes
|
||||
* @build jdk.jfr.event.runtime.TestClassRedefinition
|
||||
*
|
||||
* @run driver jdk.test.lib.util.JavaAgentBuilder
|
||||
* jdk.jfr.event.runtime.TestClassRedefinition TestClassRedefinition.jar
|
||||
*
|
||||
* @run main/othervm -javaagent:TestClassRedefinition.jar
|
||||
* jdk.jfr.event.runtime.TestClassRedefinition
|
||||
*/
|
||||
public class TestClassRedefinition {
|
||||
private final static Path DUMP_PATH = Paths.get("dump.jfr");
|
||||
|
||||
// Called when agent is loaded from command line
|
||||
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||
try (Recording r = new Recording()) {
|
||||
r.enable(EventNames.ClassRedefinition);
|
||||
r.start();
|
||||
byte[] worldBytes = Bytes.classBytes(RedefinableClass.class);
|
||||
byte[] earthBytes = Bytes.replaceAll(worldBytes, Bytes.WORLD, Bytes.EARTH);
|
||||
RedefinableClass.sayHello();
|
||||
ClassDefinition cd1 = new ClassDefinition(RedefinableClass.class, earthBytes);
|
||||
instrumentation.redefineClasses(cd1);
|
||||
RedefinableClass.sayHello();
|
||||
ClassDefinition cd2 = new ClassDefinition(RedefinableClass.class, worldBytes);
|
||||
instrumentation.redefineClasses(cd2);
|
||||
RedefinableClass.sayHello();
|
||||
r.stop();
|
||||
r.dump(DUMP_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
List<RecordedEvent> events = RecordingFile.readAllEvents(DUMP_PATH);
|
||||
|
||||
Asserts.assertEquals(events.size(), 2, "Expected exactly two ClassRedefinition event");
|
||||
RecordedEvent e1 = events.get(0);
|
||||
System.out.println(e1);
|
||||
RecordedEvent e2 = events.get(1);
|
||||
System.out.println(e2);
|
||||
|
||||
Events.assertField(e1, "classModificationCount").equal(1);
|
||||
Events.assertField(e2, "classModificationCount").equal(2);
|
||||
|
||||
Events.assertField(e1, "redefinitionId").atLeast(1L);
|
||||
Events.assertField(e2, "redefinitionId").notEqual(e1.getValue("redefinitionId"));
|
||||
|
||||
RecordedClass clazz1 = e1.getClass("redefinedClass");
|
||||
Asserts.assertEquals(clazz1.getName(), RedefinableClass.class.getName());
|
||||
RecordedClass clazz2 = e1.getClass("redefinedClass");
|
||||
Asserts.assertEquals(clazz2.getName(), RedefinableClass.class.getName());
|
||||
}
|
||||
}
|
98
test/jdk/jdk/jfr/event/runtime/TestRedefineClasses.java
Normal file
98
test/jdk/jdk/jfr/event/runtime/TestRedefineClasses.java
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.instrument.ClassDefinition;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
import jdk.test.lib.jfr.Events;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Tests RedefinitionClasses event by redefining a class in a Java
|
||||
* agent
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib /test/jdk
|
||||
* @modules java.instrument
|
||||
*
|
||||
* @build jdk.jfr.event.runtime.RedefinableClass
|
||||
* @build jdk.jfr.event.runtime.Bytes
|
||||
* @build jdk.jfr.event.runtime.TestRedefineClasses
|
||||
*
|
||||
* @run driver jdk.test.lib.util.JavaAgentBuilder
|
||||
* jdk.jfr.event.runtime.TestRedefineClasses
|
||||
* TestRedefineClasses.jar
|
||||
*
|
||||
* @run main/othervm -javaagent:TestRedefineClasses.jar
|
||||
* jdk.jfr.event.runtime.TestRedefineClasses
|
||||
*/
|
||||
public class TestRedefineClasses {
|
||||
private final static Path DUMP_PATH = Paths.get("dump.jfr");
|
||||
private final static String TEST_AGENT = "Test Agent";
|
||||
|
||||
// Called when agent is loaded at startup
|
||||
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||
Thread.currentThread().setName(TEST_AGENT);
|
||||
try (Recording r = new Recording()) {
|
||||
r.enable(EventNames.RedefineClasses);
|
||||
r.start();
|
||||
RedefinableClass.sayHello();
|
||||
byte[] bytes = Bytes.classBytes(RedefinableClass.class);
|
||||
bytes = Bytes.replaceAll(bytes, Bytes.WORLD, Bytes.EARTH);
|
||||
ClassDefinition c1 = new ClassDefinition(RedefinableClass.class, bytes);
|
||||
instrumentation.redefineClasses(c1);
|
||||
RedefinableClass.sayHello();
|
||||
r.stop();
|
||||
r.dump(DUMP_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
List<RecordedEvent> events = RecordingFile.readAllEvents(DUMP_PATH);
|
||||
Asserts.assertEquals(events.size(), 1, "Expected one RedefineClasses event");
|
||||
RecordedEvent event = events.get(0);
|
||||
|
||||
System.out.println(event);
|
||||
|
||||
Events.assertField(event, "eventThread.javaName").equal(TEST_AGENT);
|
||||
Events.assertField(event, "classCount").equal(1);
|
||||
Events.assertField(event, "redefinitionId").atLeast(1L);
|
||||
Events.assertField(event, "duration").atLeast(1L);
|
||||
Events.assertFrame(event, TestRedefineClasses.class, "premain");
|
||||
}
|
||||
}
|
100
test/jdk/jdk/jfr/event/runtime/TestRetransformClasses.java
Normal file
100
test/jdk/jdk/jfr/event/runtime/TestRetransformClasses.java
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.jfr.event.runtime;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.instrument.ClassFileTransformer;
|
||||
import java.lang.instrument.IllegalClassFormatException;
|
||||
import java.lang.instrument.Instrumentation;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.List;
|
||||
|
||||
import jdk.jfr.Recording;
|
||||
import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.lib.jfr.EventNames;
|
||||
import jdk.test.lib.jfr.Events;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @summary Tests the RetransformClasses event by redefining a class in a Java
|
||||
* agent
|
||||
* @key jfr
|
||||
* @requires vm.hasJFR
|
||||
* @library /test/lib /test/jdk
|
||||
* @modules java.instrument
|
||||
*
|
||||
* @build jdk.jfr.event.runtime.RedefinableClass
|
||||
* @build jdk.jfr.event.runtime.Bytes
|
||||
* @build jdk.jfr.event.runtime.TestRetransformClasses
|
||||
*
|
||||
* @run driver jdk.test.lib.util.JavaAgentBuilder
|
||||
* jdk.jfr.event.runtime.TestRetransformClasses TestRetransformClasses.jar
|
||||
*
|
||||
* @run main/othervm -javaagent:TestRetransformClasses.jar
|
||||
* jdk.jfr.event.runtime.TestRetransformClasses
|
||||
*/
|
||||
public class TestRetransformClasses {
|
||||
private final static Path DUMP_PATH = Paths.get("dump.jfr");
|
||||
private final static String TEST_AGENT = "Test Agent";
|
||||
|
||||
public static class TestClassFileTransformer implements ClassFileTransformer {
|
||||
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
|
||||
return Bytes.replaceAll(classfileBuffer, Bytes.WORLD, Bytes.EARTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when agent is loaded at startup
|
||||
public static void premain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||
Thread.currentThread().setName(TEST_AGENT);
|
||||
try (Recording r = new Recording()) {
|
||||
r.enable(EventNames.RetransformClasses);
|
||||
r.start();
|
||||
RedefinableClass.sayHello();
|
||||
instrumentation.addTransformer(new TestClassFileTransformer());
|
||||
instrumentation.retransformClasses(RedefinableClass.class);
|
||||
RedefinableClass.sayHello();
|
||||
r.stop();
|
||||
r.dump(DUMP_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
List<RecordedEvent> events = RecordingFile.readAllEvents(DUMP_PATH);
|
||||
Asserts.assertEquals(events.size(), 1, "Expected one RetransformClasses event");
|
||||
RecordedEvent event = events.get(0);
|
||||
|
||||
System.out.println(event);
|
||||
|
||||
Events.assertField(event, "eventThread.javaName").equal(TEST_AGENT);
|
||||
Events.assertField(event, "classCount").equal(1);
|
||||
Events.assertField(event, "redefinitionId").atLeast(1L);
|
||||
Events.assertField(event, "duration").atLeast(1L);
|
||||
Events.assertFrame(event, TestRetransformClasses.class, "premain");
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user