use mock context to store invocation record

This commit is contained in:
金戟 2021-02-13 16:26:47 +08:00
parent 9a22f361f3
commit 374a4d5442
8 changed files with 37 additions and 57 deletions

View File

@ -13,16 +13,20 @@ import java.lang.instrument.Instrumentation;
public class PreMain {
private static final String AND = "&";
private static final String USE_THREAD_POOL = "useThreadPool";
private static final String LOG_LEVEL = "logLevel";
private static final String DUMP_PATH = "dumpPath";
private static final String PKG_PREFIX = "pkgPrefix";
private static final String EQUAL = "=";
private static boolean enhanceThreadLocal = false;
public static void premain(String agentArgs, Instrumentation inst) {
// add transmittable thread local transformer
TtlAgent.premain(agentArgs, inst);
// add testable mock transformer
parseArgs(agentArgs);
if (enhanceThreadLocal) {
// add transmittable thread local transformer
TtlAgent.premain(agentArgs, inst);
}
// add testable mock transformer
inst.addTransformer(new TestableClassTransformer());
}
@ -33,6 +37,7 @@ public class PreMain {
for (String a : args.split(AND)) {
int i = a.indexOf(EQUAL);
if (i > 0) {
// parameter with key = value
String k = a.substring(0, i);
String v = a.substring(i + 1);
if (k.equals(LOG_LEVEL)) {
@ -43,7 +48,10 @@ public class PreMain {
GlobalConfig.setPkgPrefix(v);
}
} else {
GlobalConfig.setLogLevel(a);
// parameter with single value
if (a.equals(USE_THREAD_POOL)) {
enhanceThreadLocal = true;
}
}
}
}

View File

@ -4,8 +4,6 @@ import com.alibaba.testable.agent.constant.ConstPool;
import com.alibaba.testable.agent.tool.ImmutablePair;
import com.alibaba.testable.agent.util.AnnotationUtil;
import com.alibaba.testable.agent.util.ClassUtil;
import com.alibaba.testable.core.util.InvokeRecordUtil;
import com.alibaba.testable.core.util.TestableUtil;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;

View File

@ -1,6 +1,6 @@
package com.alibaba.testable.agent.model;
import com.alibaba.testable.agent.tool.UnnullableMap;
import com.alibaba.testable.core.util.UnnullableMap;
import java.util.HashMap;
import java.util.Map;

View File

@ -2,7 +2,6 @@ package com.alibaba.testable.core.matcher;
import com.alibaba.testable.core.error.VerifyFailedError;
import com.alibaba.testable.core.model.Verification;
import com.alibaba.testable.core.util.InvokeRecordUtil;
import com.alibaba.testable.core.util.MockContextUtil;
import com.alibaba.testable.core.util.TestableUtil;
@ -27,10 +26,7 @@ public class InvokeVerifier {
* @return the verifier object
*/
public static InvokeVerifier verify(String mockMethodName) {
String testClass = MockContextUtil.context.get().testClassName;
String testCaseName = MockContextUtil.context.get().testCaseName;
String recordIdentify = InvokeRecordUtil.getInvokeIdentify(mockMethodName, testClass, testCaseName);
return new InvokeVerifier(InvokeRecordUtil.getInvokeRecord(recordIdentify));
return new InvokeVerifier(MockContextUtil.invokeRecord().get(mockMethodName));
}
/**

View File

@ -1,6 +1,10 @@
package com.alibaba.testable.core.model;
import com.alibaba.testable.core.util.UnnullableMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MockContext {
@ -11,9 +15,12 @@ public class MockContext {
public final Map<String, Object> parameters;
public final Map<String, List<Object[]>> invokeRecord;
public MockContext(String testClassName, String testCaseName) {
this.testClassName = testClassName;
this.testCaseName = testCaseName;
this.parameters = new HashMap<String, Object>();
this.invokeRecord = UnnullableMap.of(new ArrayList<Object[]>());
}
}

View File

@ -1,21 +1,10 @@
package com.alibaba.testable.core.util;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
/**
* @author flin
*/
public class InvokeRecordUtil {
/**
* Mock method name List of invoke parameters
*/
private static final Map<String, List<Object[]>> INVOKE_RECORDS = new HashMap<String, List<Object[]>>();
private final static String JOINER = "::";
/**
* [0]Thread [1]TestableUtil/TestableTool [2]TestClass
*/
@ -32,37 +21,13 @@ public class InvokeRecordUtil {
String mockMethodName = mockMethodTraceElement.getMethodName();
String testClass = MockContextUtil.context.get().testClassName;
String testCaseName = MockContextUtil.context.get().testCaseName;
String identify = getInvokeIdentify(mockMethodName, testClass, testCaseName);
List<Object[]> records = getInvokeRecord(identify);
if (isConstructor) {
records.add(args);
LogUtil.verbose(" Mock constructor invoked \"%s\"", identify);
MockContextUtil.invokeRecord().get(mockMethodName).add(args);
LogUtil.verbose(" Mock constructor \"%s\" invoked in %s::%s", mockMethodName, testClass, testCaseName);
} else {
records.add(isTargetClassInParameter ? slice(args, 1) : args);
LogUtil.verbose(" Mock method invoked \"%s\"", identify);
MockContextUtil.invokeRecord().get(mockMethodName).add(isTargetClassInParameter ? slice(args, 1) : args);
LogUtil.verbose(" Mock method \"%s\" invoked in %s::%s\"", mockMethodName, testClass, testCaseName);
}
INVOKE_RECORDS.put(identify, records);
}
/**
* Get identify key for mock invocation record
* @param mockMethodName mock method name
* @param testClass test class name
* @param testCaseName test case name
* @return identify key
*/
public static String getInvokeIdentify(String mockMethodName, String testClass, String testCaseName) {
return testClass + JOINER + testCaseName + JOINER + mockMethodName;
}
/**
* Get mock method invoke count
* @param identify key of invocation record
* @return parameters used when specified method invoked in specified test case
*/
public static List<Object[]> getInvokeRecord(String identify) {
List<Object[]> records = INVOKE_RECORDS.get(identify);
return (records == null) ? new LinkedList<Object[]>() : records;
}
private static Object[] slice(Object[] args, int firstIndex) {

View File

@ -3,9 +3,12 @@ package com.alibaba.testable.core.util;
import com.alibaba.testable.core.model.MockContext;
import com.alibaba.ttl.TransmittableThreadLocal;
import java.util.List;
import java.util.Map;
public class MockContextUtil {
public static TransmittableThreadLocal<MockContext> context = new TransmittableThreadLocal<MockContext>();
public static InheritableThreadLocal<MockContext> context = new TransmittableThreadLocal<MockContext>();
/**
* Should be invoked at the beginning of each test case method
@ -21,8 +24,11 @@ public class MockContextUtil {
context.remove();
}
public static String testCaseMark() {
MockContext context = MockContextUtil.context.get();
return context.testClassName + "::" + context.testCaseName;
public static Map<String, Object> parameters() {
return MockContextUtil.context.get().parameters;
}
public static Map<String, List<Object[]>> invokeRecord() {
return MockContextUtil.context.get().invokeRecord;
}
}

View File

@ -1,4 +1,4 @@
package com.alibaba.testable.agent.tool;
package com.alibaba.testable.core.util;
import com.alibaba.testable.core.accessor.PrivateAccessor;
@ -15,7 +15,7 @@ public class UnnullableMap<K, V> extends HashMap<K, V> {
this.defaultValue = defaultValue;
}
public static <K, V> UnnullableMap<K, V> of(V defaultValue) {
public static <K, V, T extends V> UnnullableMap<K, V> of(T defaultValue) {
return new UnnullableMap<K, V>(defaultValue);
}