mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-02-05 01:01:02 +08:00
avoid source class be re-transformed
This commit is contained in:
parent
13fa8a76ce
commit
28bb6454c8
@ -1,17 +1,35 @@
|
|||||||
package com.alibaba.testable.agent.handler;
|
package com.alibaba.testable.agent.handler;
|
||||||
|
|
||||||
|
import com.alibaba.testable.core.util.LogUtil;
|
||||||
import org.objectweb.asm.ClassReader;
|
import org.objectweb.asm.ClassReader;
|
||||||
import org.objectweb.asm.ClassWriter;
|
import org.objectweb.asm.ClassWriter;
|
||||||
import org.objectweb.asm.Opcodes;
|
import org.objectweb.asm.Opcodes;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.FieldNode;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author flin
|
* @author flin
|
||||||
*/
|
*/
|
||||||
abstract public class BaseClassHandler implements Opcodes {
|
abstract public class BaseClassHandler implements Opcodes {
|
||||||
|
|
||||||
|
protected static final String TESTABLE_MARK_FIELD = "__testable";
|
||||||
|
|
||||||
|
protected boolean wasTransformed(ClassNode cn) {
|
||||||
|
Iterator<FieldNode> iterator = cn.fields.iterator();
|
||||||
|
if (iterator.hasNext()) {
|
||||||
|
if (TESTABLE_MARK_FIELD.equals(iterator.next().name)) {
|
||||||
|
// avoid duplicate injection
|
||||||
|
LogUtil.verbose("Duplicate injection found, ignore " + cn.name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cn.fields.add(new FieldNode(ACC_PRIVATE, TESTABLE_MARK_FIELD, "I", null, null));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public byte[] getBytes(byte[] classFileBuffer) throws IOException {
|
public byte[] getBytes(byte[] classFileBuffer) throws IOException {
|
||||||
ClassReader cr = new ClassReader(classFileBuffer);
|
ClassReader cr = new ClassReader(classFileBuffer);
|
||||||
ClassNode cn = new ClassNode();
|
ClassNode cn = new ClassNode();
|
||||||
|
@ -36,6 +36,9 @@ public class SourceClassHandler extends BaseClassHandler {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected void transform(ClassNode cn) {
|
protected void transform(ClassNode cn) {
|
||||||
|
if (wasTransformed(cn)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
Set<MethodInfo> memberInjectMethods = new HashSet<MethodInfo>();
|
Set<MethodInfo> memberInjectMethods = new HashSet<MethodInfo>();
|
||||||
Set<MethodInfo> newOperatorInjectMethods = new HashSet<MethodInfo>();
|
Set<MethodInfo> newOperatorInjectMethods = new HashSet<MethodInfo>();
|
||||||
for (MethodInfo mi : injectMethods) {
|
for (MethodInfo mi : injectMethods) {
|
||||||
|
@ -7,7 +7,6 @@ import com.alibaba.testable.agent.util.ClassUtil;
|
|||||||
import com.alibaba.testable.core.util.LogUtil;
|
import com.alibaba.testable.core.util.LogUtil;
|
||||||
import org.objectweb.asm.tree.*;
|
import org.objectweb.asm.tree.*;
|
||||||
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static com.alibaba.testable.agent.util.ClassUtil.toDotSeparateFullClassName;
|
import static com.alibaba.testable.agent.util.ClassUtil.toDotSeparateFullClassName;
|
||||||
@ -20,7 +19,6 @@ public class TestClassHandler extends BaseClassHandler {
|
|||||||
private static final String CLASS_TESTABLE_TOOL = "com/alibaba/testable/core/tool/TestableTool";
|
private static final String CLASS_TESTABLE_TOOL = "com/alibaba/testable/core/tool/TestableTool";
|
||||||
private static final String CLASS_TESTABLE_UTIL = "com/alibaba/testable/core/util/TestableUtil";
|
private static final String CLASS_TESTABLE_UTIL = "com/alibaba/testable/core/util/TestableUtil";
|
||||||
private static final String CLASS_INVOKE_RECORD_UTIL = "com/alibaba/testable/core/util/InvokeRecordUtil";
|
private static final String CLASS_INVOKE_RECORD_UTIL = "com/alibaba/testable/core/util/InvokeRecordUtil";
|
||||||
private static final String TESTABLE_MARK_FIELD = "__testable";
|
|
||||||
private static final String FIELD_TEST_CASE = "TEST_CASE";
|
private static final String FIELD_TEST_CASE = "TEST_CASE";
|
||||||
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD";
|
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD";
|
||||||
private static final String METHOD_CURRENT_TEST_CASE_NAME = "currentTestCaseName";
|
private static final String METHOD_CURRENT_TEST_CASE_NAME = "currentTestCaseName";
|
||||||
@ -40,32 +38,19 @@ public class TestClassHandler extends BaseClassHandler {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (MethodNode mn : cn.methods) {
|
for (MethodNode mn : cn.methods) {
|
||||||
handleMockMethod(mn);
|
handleMockMethod(cn, mn);
|
||||||
handleInstruction(cn, mn);
|
handleInstruction(cn, mn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean wasTransformed(ClassNode cn) {
|
private void handleMockMethod(ClassNode cn, MethodNode mn) {
|
||||||
Iterator<FieldNode> iterator = cn.fields.iterator();
|
|
||||||
if (iterator.hasNext()) {
|
|
||||||
if (TESTABLE_MARK_FIELD.equals(iterator.next().name)) {
|
|
||||||
// avoid duplicate injection
|
|
||||||
LogUtil.verbose("Duplicate injection found, ignore " + cn.name);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cn.fields.add(new FieldNode(ACC_PRIVATE, TESTABLE_MARK_FIELD, "I", null, null));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleMockMethod(MethodNode mn) {
|
|
||||||
if (isMockMethod(mn)) {
|
if (isMockMethod(mn)) {
|
||||||
toPublicStatic(mn);
|
toPublicStatic(cn, mn);
|
||||||
injectInvokeRecorder(mn);
|
injectInvokeRecorder(mn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void toPublicStatic(MethodNode mn) {
|
private void toPublicStatic(ClassNode cn, MethodNode mn) {
|
||||||
mn.access &= ~ACC_PRIVATE;
|
mn.access &= ~ACC_PRIVATE;
|
||||||
mn.access &= ~ACC_PROTECTED;
|
mn.access &= ~ACC_PROTECTED;
|
||||||
mn.access |= ACC_PUBLIC;
|
mn.access |= ACC_PUBLIC;
|
||||||
|
@ -45,7 +45,6 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
ProtectionDomain protectionDomain, byte[] classFileBuffer) {
|
ProtectionDomain protectionDomain, byte[] classFileBuffer) {
|
||||||
if (isSystemClass(className)) {
|
if (isSystemClass(className)) {
|
||||||
// Ignore system class and reloaded class
|
// Ignore system class and reloaded class
|
||||||
LogUtil.verbose("Ignore class: " + (className == null ? "<lambda>" : className));
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
LogUtil.verbose("Handle class: " + className);
|
LogUtil.verbose("Handle class: " + className);
|
||||||
@ -65,8 +64,9 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
dumpByte(className, bytes);
|
dumpByte(className, bytes);
|
||||||
resetMockContext();
|
resetMockContext();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (Throwable t) {
|
||||||
LogUtil.warn("Failed to transform class " + className);
|
LogUtil.warn("Failed to transform class " + className);
|
||||||
|
LogUtil.diagnose(t.toString());
|
||||||
}
|
}
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
@ -77,7 +77,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String dumpFile = StringUtil.joinPath(dumpDir, className.replaceAll("/", "_") + ".class");
|
String dumpFile = StringUtil.joinPath(dumpDir, className.replaceAll("/", ".") + ".class");
|
||||||
|
LogUtil.verbose("Dump class: " + dumpFile);
|
||||||
FileOutputStream stream = new FileOutputStream(dumpFile);
|
FileOutputStream stream = new FileOutputStream(dumpFile);
|
||||||
stream.write(bytes);
|
stream.write(bytes);
|
||||||
stream.close();
|
stream.close();
|
||||||
|
Loading…
Reference in New Issue
Block a user