avoid source class be re-transformed

This commit is contained in:
金戟 2020-12-27 11:34:25 +08:00
parent 13fa8a76ce
commit 28bb6454c8
4 changed files with 29 additions and 22 deletions

View File

@ -1,17 +1,35 @@
package com.alibaba.testable.agent.handler;
import com.alibaba.testable.core.util.LogUtil;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode;
import java.io.IOException;
import java.util.Iterator;
/**
* @author flin
*/
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 {
ClassReader cr = new ClassReader(classFileBuffer);
ClassNode cn = new ClassNode();

View File

@ -36,6 +36,9 @@ public class SourceClassHandler extends BaseClassHandler {
*/
@Override
protected void transform(ClassNode cn) {
if (wasTransformed(cn)) {
return;
}
Set<MethodInfo> memberInjectMethods = new HashSet<MethodInfo>();
Set<MethodInfo> newOperatorInjectMethods = new HashSet<MethodInfo>();
for (MethodInfo mi : injectMethods) {

View File

@ -7,7 +7,6 @@ import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.core.util.LogUtil;
import org.objectweb.asm.tree.*;
import java.util.Iterator;
import java.util.List;
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_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 TESTABLE_MARK_FIELD = "__testable";
private static final String FIELD_TEST_CASE = "TEST_CASE";
private static final String FIELD_SOURCE_METHOD = "SOURCE_METHOD";
private static final String METHOD_CURRENT_TEST_CASE_NAME = "currentTestCaseName";
@ -40,32 +38,19 @@ public class TestClassHandler extends BaseClassHandler {
return;
}
for (MethodNode mn : cn.methods) {
handleMockMethod(mn);
handleMockMethod(cn, mn);
handleInstruction(cn, mn);
}
}
private 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;
}
private void handleMockMethod(MethodNode mn) {
private void handleMockMethod(ClassNode cn, MethodNode mn) {
if (isMockMethod(mn)) {
toPublicStatic(mn);
toPublicStatic(cn, mn);
injectInvokeRecorder(mn);
}
}
private void toPublicStatic(MethodNode mn) {
private void toPublicStatic(ClassNode cn, MethodNode mn) {
mn.access &= ~ACC_PRIVATE;
mn.access &= ~ACC_PROTECTED;
mn.access |= ACC_PUBLIC;

View File

@ -45,7 +45,6 @@ public class TestableClassTransformer implements ClassFileTransformer {
ProtectionDomain protectionDomain, byte[] classFileBuffer) {
if (isSystemClass(className)) {
// Ignore system class and reloaded class
LogUtil.verbose("Ignore class: " + (className == null ? "<lambda>" : className));
return null;
}
LogUtil.verbose("Handle class: " + className);
@ -65,8 +64,9 @@ public class TestableClassTransformer implements ClassFileTransformer {
dumpByte(className, bytes);
resetMockContext();
}
} catch (IOException e) {
} catch (Throwable t) {
LogUtil.warn("Failed to transform class " + className);
LogUtil.diagnose(t.toString());
}
return bytes;
}
@ -77,7 +77,8 @@ public class TestableClassTransformer implements ClassFileTransformer {
return;
}
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);
stream.write(bytes);
stream.close();