diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/BaseClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/BaseClassHandler.java index d64d811..e36a198 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/BaseClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/BaseClassHandler.java @@ -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 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(); diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java index cbe231a..64d2046 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/SourceClassHandler.java @@ -36,6 +36,9 @@ public class SourceClassHandler extends BaseClassHandler { */ @Override protected void transform(ClassNode cn) { + if (wasTransformed(cn)) { + return; + } Set memberInjectMethods = new HashSet(); Set newOperatorInjectMethods = new HashSet(); for (MethodInfo mi : injectMethods) { diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java index 1ef75ca..18036a6 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java @@ -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 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; diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java index 844d1d6..913d307 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java @@ -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 ? "" : 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();