From adfba4bac0d14d8d198de34bead3a1fa7167fdca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Fri, 5 Feb 2021 22:30:04 +0800 Subject: [PATCH] support verbose log for self diagnosing --- .../alibaba/testable/demo/DemoMockTest.java | 2 +- .../agent/handler/SourceClassHandler.java | 41 +++++++++++-------- .../transformer/TestableClassTransformer.java | 8 +++- .../testable/agent/util/ClassUtil.java | 10 +++++ .../testable/agent/util/ClassUtilTest.java | 6 +++ .../testable/core/model/MockDiagnose.java | 7 +++- .../alibaba/testable/core/util/LogUtil.java | 4 +- 7 files changed, 54 insertions(+), 24 deletions(-) diff --git a/demo/java-demo/src/test/java/com/alibaba/testable/demo/DemoMockTest.java b/demo/java-demo/src/test/java/com/alibaba/testable/demo/DemoMockTest.java index 4468466..8e1e8d6 100644 --- a/demo/java-demo/src/test/java/com/alibaba/testable/demo/DemoMockTest.java +++ b/demo/java-demo/src/test/java/com/alibaba/testable/demo/DemoMockTest.java @@ -8,8 +8,8 @@ import org.junit.jupiter.api.Test; import java.util.concurrent.Executors; import static com.alibaba.testable.core.matcher.InvokeVerifier.verify; -import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD; import static com.alibaba.testable.core.tool.TestableTool.MOCK_CONTEXT; +import static com.alibaba.testable.core.tool.TestableTool.SOURCE_METHOD; import static org.junit.jupiter.api.Assertions.assertEquals; /** 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 d299809..8b8374b 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 @@ -65,24 +65,12 @@ public class SourceClassHandler extends BaseClassHandler { do { if (invokeOps.contains(instructions[i].getOpcode())) { MethodInsnNode node = (MethodInsnNode)instructions[i]; - MethodInfo mockMethod = getMemberInjectMethodName(memberInjectMethods, node); - if (mockMethod != null) { - // it's a member or static method and an inject method for it exist - int rangeStart = getMemberMethodStart(instructions, i); - if (rangeStart >= 0) { - ModifiedInsnNodes modifiedInsnNodes = replaceMemberCallOps(cn, mn, mockMethod, - instructions, node.owner, node.getOpcode(), rangeStart, i); - instructions = modifiedInsnNodes.nodes; - maxStackDiff = Math.max(maxStackDiff, modifiedInsnNodes.stackDiff); - i = rangeStart; - } else { - LogUtil.warn("Potential missed mocking at %s:%s", mn.name, getLineNum(instructions, i)); - } - } else if (ConstPool.CONSTRUCTOR.equals(node.name)) { - // it's a new operation + if (ConstPool.CONSTRUCTOR.equals(node.name)) { + LogUtil.verbose(" Line %d, constructing \"%s\" as \"%s\"", getLineNum(instructions, i), + node.owner, node.desc); String newOperatorInjectMethodName = getNewOperatorInjectMethodName(newOperatorInjectMethods, node); if (newOperatorInjectMethodName != null) { - // and an inject method for it exist + // it's a new operation and an inject method for it exist int rangeStart = getConstructorStart(instructions, node.owner, i); if (rangeStart >= 0) { ModifiedInsnNodes modifiedInsnNodes = replaceNewOps(cn, mn, newOperatorInjectMethodName, @@ -92,6 +80,23 @@ public class SourceClassHandler extends BaseClassHandler { i = rangeStart; } } + } else { + LogUtil.verbose(" Line %d, invoking \"%s\" as \"%s\"", getLineNum(instructions, i), + node.name, node.desc); + MethodInfo mockMethod = getMemberInjectMethodName(memberInjectMethods, node); + if (mockMethod != null) { + // it's a member or static method and an inject method for it exist + int rangeStart = getMemberMethodStart(instructions, i); + if (rangeStart >= 0) { + ModifiedInsnNodes modifiedInsnNodes = replaceMemberCallOps(cn, mn, mockMethod, + instructions, node.owner, node.getOpcode(), rangeStart, i); + instructions = modifiedInsnNodes.nodes; + maxStackDiff = Math.max(maxStackDiff, modifiedInsnNodes.stackDiff); + i = rangeStart; + } else { + LogUtil.warn("Potential missed mocking at %s:%s", mn.name, getLineNum(instructions, i)); + } + } } } i++; @@ -194,7 +199,7 @@ public class SourceClassHandler extends BaseClassHandler { private ModifiedInsnNodes replaceNewOps(ClassNode cn, MethodNode mn, String newOperatorInjectMethodName, AbstractInsnNode[] instructions, int start, int end) { - LogUtil.diagnose(" Line %d, mock method %s used", getLineNum(instructions, start), + LogUtil.diagnose(" Line %d, mock method \"%s\" used", getLineNum(instructions, start), newOperatorInjectMethodName); String classType = ((TypeInsnNode)instructions[start]).desc; String constructorDesc = ((MethodInsnNode)instructions[end]).desc; @@ -224,7 +229,7 @@ public class SourceClassHandler extends BaseClassHandler { private ModifiedInsnNodes replaceMemberCallOps(ClassNode cn, MethodNode mn, MethodInfo mockMethod, AbstractInsnNode[] instructions, String ownerClass, int opcode, int start, int end) { - LogUtil.diagnose(" Line %d, mock method %s used", getLineNum(instructions, start), + LogUtil.diagnose(" Line %d, mock method \"%s\" used", getLineNum(instructions, start), mockMethod.getMockName()); boolean shouldAppendTypeParameter = !mockMethod.getDesc().equals(mockMethod.getMockDesc()); String testClassName = ClassUtil.getTestClassName(cn.name); 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 3556000..46d8799 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 @@ -57,8 +57,8 @@ public class TestableClassTransformer implements ClassFileTransformer { try { if (shouldTransformAsSourceClass(className)) { // it's a source class with testable enabled - LogUtil.diagnose("Handling source class %s", className); List injectMethods = getTestableMockMethods(ClassUtil.getTestClassName(className)); + LogUtil.diagnose("Handling source class %s", className); bytes = new SourceClassHandler(injectMethods).getBytes(classFileBuffer); dumpByte(className, bytes); resetMockContext(); @@ -140,9 +140,12 @@ public class TestableClassTransformer implements ClassFileTransformer { for (AnnotationNode an : mn.visibleAnnotations) { String fullClassName = toDotSeparateFullClassName(an.desc); if (fullClassName.equals(ConstPool.MOCK_CONSTRUCTOR)) { + LogUtil.verbose(" Mock constructor \"%s\" as \"(%s)V\" for \"%s\"", mn.name, + ClassUtil.extractParameters(mn.desc), ClassUtil.getReturnType(mn.desc)); addMockConstructor(methodInfos, cn, mn); } else if (fullClassName.equals(ConstPool.MOCK_METHOD) || fullClassName.equals(ConstPool.TESTABLE_MOCK)) { + LogUtil.verbose(" Mock method \"%s\" as \"%s\"", mn.name, mn.desc); String targetMethod = AnnotationUtil.getAnnotationParameter( an, ConstPool.FIELD_TARGET_METHOD, mn.name, String.class); if (ConstPool.CONSTRUCTOR.equals(targetMethod)) { @@ -218,7 +221,8 @@ public class TestableClassTransformer implements ClassFileTransformer { private void setupMockContext(AnnotationNode an) { MockDiagnose diagnose = AnnotationUtil.getAnnotationParameter(an, FIELD_DIAGNOSE, null, MockDiagnose.class); if (diagnose != null) { - LogUtil.enableDiagnose(diagnose == MockDiagnose.ENABLE); + LogUtil.setLevel(diagnose == MockDiagnose.ENABLE ? LogUtil.LogLevel.LEVEL_DIAGNOSE : + (diagnose == MockDiagnose.VERBOSE ? LogUtil.LogLevel.LEVEL_VERBOSE : LogUtil.LogLevel.LEVEL_MUTE)); } } diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/util/ClassUtil.java b/testable-agent/src/main/java/com/alibaba/testable/agent/util/ClassUtil.java index bb504ad..0f29cc5 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/util/ClassUtil.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/util/ClassUtil.java @@ -140,6 +140,16 @@ public class ClassUtil { return parameterTypes; } + /** + * extract parameter part of method desc + * @param desc method description + * @return parameter value + */ + public static String extractParameters(String desc) { + int returnTypeEdge = desc.lastIndexOf(PARAM_END); + return desc.substring(1, returnTypeEdge); + } + /** * parse method desc, fetch return value types * @param desc method description diff --git a/testable-agent/src/test/java/com/alibaba/testable/agent/util/ClassUtilTest.java b/testable-agent/src/test/java/com/alibaba/testable/agent/util/ClassUtilTest.java index 04ed8e3..84883f0 100644 --- a/testable-agent/src/test/java/com/alibaba/testable/agent/util/ClassUtilTest.java +++ b/testable-agent/src/test/java/com/alibaba/testable/agent/util/ClassUtilTest.java @@ -15,6 +15,12 @@ class ClassUtilTest { assertEquals(3, ClassUtil.getParameterTypes("(Ljava/lang/String;[I[Ljava/lang/String;)V").size()); } + @Test + void should_able_to_extract_parameter() { + assertEquals("", ClassUtil.extractParameters("()I")); + assertEquals("Ljava/lang/String;", ClassUtil.extractParameters("(Ljava/lang/String;)I")); + } + @Test void should_able_to_get_return_type() { assertEquals("", ClassUtil.getReturnType("(Ljava/lang/String;)V")); diff --git a/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java b/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java index ff781e5..7e78ca1 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/model/MockDiagnose.java @@ -14,6 +14,11 @@ public enum MockDiagnose { /** * Print diagnose logs */ - ENABLE + ENABLE, + + /** + * Print verbose log + */ + VERBOSE } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/util/LogUtil.java b/testable-core/src/main/java/com/alibaba/testable/core/util/LogUtil.java index c0c0695..f671d86 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/util/LogUtil.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/util/LogUtil.java @@ -54,8 +54,8 @@ public class LogUtil { System.err.println(String.format("[ERROR] " + msg, args)); } - public static void enableDiagnose(boolean enable) { - currentLogLevel = enable ? LogLevel.LEVEL_DIAGNOSE : LogLevel.LEVEL_MUTE; + public static void setLevel(LogLevel level) { + currentLogLevel = level; } public static void setDefaultLevel(LogLevel level) {